ElementUI table自带的有一个highlight-current-row
的属性,但是只能单选。所以要实现点击行选中以及多选得自己实现.
目标:单击选中/取消, 按ctrl
键点击实现多选 ,按shift/alt
键实现连续多选。
实现效果
1. 监听row-click
事件,实现选中
.....
.....
rowClick(row, column, event) {
let refsElTable = this.$refs.multipleTable; // 获取表格对象
refsElTable.toggleRowSelection(row); // 调用选中行方法
}
2. 实现选中取消,以及单个选中
上面已经实现点击选中,但是会点击一行选中一行,所以要使用clearSelection
先清空之前选择的行,然后进行选择,取消选择首先要确定当前点击的行是否被已被选中,所以先监听selection-change
事件保存已选中行(或者使用$refs
获取内部保存的已选择行),以及使用row-style
给每一行添加唯一标识。
rowClick(row, column, event) {
let refsElTable = this.$refs.multipleTable; // 获取表格对象
let findRow = this.selectionRow.find(c => c.rowIndex == row.rowIndex);
if (findRow ) {
refsElTable.toggleRowSelection(row, false);
return;
}
refsElTable.clearSelection();
refsElTable.toggleRowSelection(row); // 调用选中行方法
},
rowStyle({row,rowIndex}) {
Object.defineProperty(row, 'rowIndex', { //给每一行添加不可枚举属性rowIndex来标识当前行
value: rowIndex,
writable: true,
enumerable: false
})
},
handleSelectionChange(rows) {
this.selectionRow = rows //保存已选择行
},
3. 按住ctrl
实现多选
首先要监听keydown
事件,以及keyup
事件,
methods: {
rowClick(row, column, event) {
let refsElTable = this.$refs.multipleTable; // 获取表格对象
if (this.CtrlDown) {
refsElTable.toggleRowSelection(row); // ctrl多选 如果点击两次同样会取消选中
return;
}
let findRow = this.selectionRow.find(c => c.rowIndex == row.rowIndex);
if (findRow ) {
refsElTable.toggleRowSelection(row, false);
return;
}
refsElTable.clearSelection();
refsElTable.toggleRowSelection(row); // 调用选中行方法
},
keyDown(event) {
let key = event.keyCode;
if (key == 17) this.CtrlDown = true;
},
keyUp(event) {
let key = event.keyCode;
if (key == 17) this.CtrlDown = false;
},
},
mounted() {
addEventListener("keydown", this.keyDown, false);
addEventListener("keyup", this.keyUp, false);
},
beforeDestroy() { //解绑
removeEventListener("keydown", this.keyDown);
removeEventListener("keyup", this.keyUp);
}
4. shift/alt
键实现连续多选
这一步要通过rowIndex
判断已选择的行中最上面和最下面的是哪行,再对比按住shift/alt
点击的当前行得到新的最上面和最下面的行,把这两行中间的行进行循环选中。
computed: { //实时得到最上行和最下行
bottomSelectionRow() {
if (this.selectionRow.length == 0) return null;
return this.selectionRow.reduce((start, end) => {
return start.rowIndex > end.rowIndex ? start : end;
});
},
topSelectionRow() {
if (this.selectionRow.length == 0) return null;
return this.selectionRow.reduce((start, end) => {
return start.rowIndex < end.rowIndex ? start : end;
});
}
},
methods: {
rowClick(row, column, event) {
let refsElTable = this.$refs.multipleTable; // 获取表格对象
if (this.CtrlDown) {
refsElTable.toggleRowSelection(row); // ctrl多选 如果点击两次同样会取消选中
return;
}
if ( this.shiftOrAltDown && this.selectionRow.length > 0) {
let topAndBottom = getTopAndBottom( row, this.bottomSelectionRow, this.topSelectionRow );
refsElTable.clearSelection(); //先清空 不然会导致在这两行中间之外的行状态不变
for (let index = topAndBottom.top; index <= topAndBottom.bottom; index++) { //选中两行之间的所有行
refsElTable.toggleRowSelection(this.tableData[index], true);
}
} else {
let findRow = this.selectionRow.find(c => c.rowIndex == row.rowIndex); //找出当前选中行
//如果只有一行且点击的也是这一行则取消选择 否则清空再选中当前点击行
if (findRow&& this.selectionRow.length === 1 ) {
refsElTable.toggleRowSelection(row, false);
return;
}
refsElTable.clearSelection();
refsElTable.toggleRowSelection(row);
}
},
rowStyle({row,rowIndex}) {
Object.defineProperty(row, 'rowIndex', { //给每一行添加不可枚举属性rowIndex来标识当前行
value: rowIndex,
writable: true,
enumerable: false
})
},
keyDown(event) {
let key = event.keyCode;
if (key == 17) this.CtrlDown = true;
if (key == 16 || key == 18) this.shiftOrAltDown = true;
},
keyUp(event) {
let key = event.keyCode;
if (key == 17) this.CtrlDown = false;
if (key == 16 || key == 18) this.shiftOrAltDown = false;
},
},
mounted() {
addEventListener("keydown", this.keyDown, false);
addEventListener("keyup", this.keyUp, false);
},
beforeDestroy() { //解绑
removeEventListener("keydown", this.keyDown);
removeEventListener("keyup", this.keyUp);
}
/**获取最新最上最下行 */
function getTopAndBottom(row, bottom, top) {
let n = row.rowIndex,
mx = bottom.rowIndex,
mi = top.rowIndex;
if (n > mx) {
return {
top: mi,
bottom: n
};
} else if (n < mx && n > mi) {
return {
top: mi,
bottom: n
};
} else if (n < mi) {
return {
top: n,
bottom: mx
};
} else if (n == mi || n == mx) {
return {
top: mi,
bottom: mx
};
}
};
5. 实现选中高亮
跟element-ui
本身的单选高亮实现方式一样,都是给选中行加上current-row
这个class
类,所以要使用row-class-name
这个属性(其实给每一行添加rowIndex
也可以用这个属性),判断方式也是通过判断rowIndex
对比
rowClassName({ row, rowIndex }) {
let rowName = "",
findRow = this.selectionRow.find(c => c.rowIndex === row.rowIndex);
if (findRow) {
rowName = "current-row "; // elementUI 默认高亮行的class类 不用再样式了^-^,也可通过css覆盖改变背景颜色
}
return rowName; //也可以再加上其他类名 如果有需求的话
},
Demo及代码
https://codepen.io/lozvoe/pen/jgeKME