- 封装
基于element-ui (vue2版), 二次封装
Vue.component('selector-table', {
template: `
<div style="width: 100%">
<el-table border :data="tableData" style="width: 100%">
<el-table-column min-width="180" align="center">
<template #header="{ column, $index }">
<div>
<el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange"></el-checkbox>
</div>
</template>
<template #default="{ row, column, $index }">
<div>
<el-checkbox v-model="row[checkboxKey]" @change="handleCheckSingleChange(row)"></el-checkbox>
</div>
</template>
</el-table-column>
<slot></slot>
<template #append>
<slot name="append"></slot>
</template>
</el-table>
</div>
`,
model: {
prop: 'selectedArr',
event: 'selectedArrChange'
},
props: {
data: {
type: Array,
default: () => []
},
selectedArr: {
type: Array,
default: () => []
},
selectorkey: {
type: String,
default: 'id'
}
},
data() {
return {
checkboxKey: Symbol(),
tableData: [],
isIndeterminate: false,
checkAll: false
};
},
watch: {
data: {
handler(val) {
const valCopy = this.deepCopy(val);
this.tableData = valCopy.map(cur => {
cur[this.checkboxKey] = false;
return cur;
});
this.tableData.forEach(cur => {
if (this.selectedArr.some(_cur => _cur[this.selectorkey] === cur[this.selectorkey])) {
cur[this.checkboxKey] = true;
} else {
cur[this.checkboxKey] = false;
}
});
this.checkIsALLSelected() ? (this.checkAll = true) : (this.checkAll = false);
this.patchBindObjNode('tableData');
},
immediate: true,
deep: true
},
selectedArr: {
handler(val) {
this.tableData.forEach(cur => {
if (val.some(_cur => _cur[this.selectorkey] === cur[this.selectorkey])) {
cur[this.checkboxKey] = true;
} else {
cur[this.checkboxKey] = false;
}
});
this.checkIsALLSelected() ? (this.checkAll = true) : (this.checkAll = false);
this.patchBindObjNode('tableData');
},
immediate: true,
deep: true
}
},
methods: {
handleCheckAllChange(val) {
let arr = [];
if (val) {
this.checkAllTrue();
arr = this.selectedArr.concat(this.deepCopy(this.tableData));
} else {
let deleteArr = [];
this.checkAllFalse();
this.tableData.forEach(cur => {
if (this.selectedArr.some(_cur => _cur[this.selectorkey] === cur[this.selectorkey])) {
deleteArr.push(cur[this.selectorkey]);
}
});
arr = this.selectedArr.filter(cur => !deleteArr.some(_cur => _cur === cur[this.selectorkey]));
}
this.$emit('selectedArrChange', this.removeSymbolProperties(this.removeDuplicateKeyItem(arr, this.selectorkey)));
},
handleCheckSingleChange(row) {
let arr = [];
if (row[this.checkboxKey]) {
arr = this.selectedArr.concat([this.deepCopy(row)]);
} else {
let deleteArr = [];
this.selectedArr.forEach(cur => {
if (cur[this.selectorkey] === row[this.selectorkey]) {
deleteArr.push(cur[this.selectorkey]);
}
});
arr = this.selectedArr.filter(cur => !deleteArr.some(_cur => _cur === cur[this.selectorkey]));
}
this.$emit('selectedArrChange', this.removeSymbolProperties(this.removeDuplicateKeyItem(arr, this.selectorkey)));
this.checkIsALLSelected() ? (this.checkAll = true) : (this.checkAll = false);
},
checkIsALLSelected() {
return !this.tableData.filter(cur => !cur[this.checkboxKey]).length;
},
checkAllTrue() {
this.tableData.forEach(cur => (cur[this.checkboxKey] = true));
},
checkAllFalse() {
this.tableData.forEach(cur => (cur[this.checkboxKey] = false));
},
deepCopy(obj, cache = []) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
const hit = cache.filter(c => c.original === obj)[0];
if (hit) {
return hit.copy;
}
const copy = Array.isArray(obj) ? [] : {};
cache.push({
original: obj,
copy
});
[...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)].forEach(key => {
copy[key] = this.deepCopy(obj[key], cache);
});
return copy;
},
removeDuplicateKeyItem(arr, key) {
return arr.reduce((acc, cur) => {
if (!acc.some(obj => obj[key] === cur[key])) {
acc.push(cur);
}
return acc;
}, []);
},
patchBindObjNode(obj) {
this[obj] = this.deepCopy(this[obj]);
},
removeSymbolProperties(arr) {
return arr.map(obj => {
const newObj = {};
Object.keys(obj).forEach(key => {
newObj[key] = obj[key];
});
return newObj;
});
}
}
});
- 笔者全局注册, 看官灵活运用
- 使用
尽可能保留了原汁原味的el-table使用方法
data: 表格数据, 和官网一样
selectedArray: 双向绑定选中的数组
@selected-arr-change: 点击复选框, 选中数组改变时触发事件
<selector-table :data="tableData" v-model="selectedArray" @selected-arr-change="fun">
<template #default>
<el-table-column prop="date" label="日期" width="180"> </el-table-column>
<el-table-column prop="name" label="姓名" width="180"> </el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column label="操作">
<template #default="{ row, column, $index }">
<el-button size="small" type="primary">编辑</el-button>
</template>
</el-table-column>
</template>
<template #append>
<div style="text-align: right; padding: 16px">
<el-pagination
@current-change="handleCurrentChange"
:current-page="1"
:page-sizes="[10, 20, 50, 100]"
:page-size="10"
layout="total, sizes, prev, pager, next, jumper"
:total="100"
>
</el-pagination>
</div>
</template>
</selector-table>
- 核心代码和思路已经完善了, 可以直接用, 你也可以加以扩展