Element UI 表格点击选中行/取消选中 快捷多选 以及快捷连续多选,高亮选中行

6,924 阅读3分钟

ElementUI table自带的有一个highlight-current-row的属性,但是只能单选。所以要实现点击行选中以及多选得自己实现.

目标:单击选中/取消, 按ctrl键点击实现多选 ,按shift/alt键实现连续多选。

实现效果

1. 监听row-click事件,实现选中

 <el-table ref="multipleTable" 
            :data="tableData"
            style="width: 100%"
            @selection-change="handleSelectionChange"
            @row-click="rowClick" 
            :row-style="rowStyle"
            :row-class-name="rowClassName">
            .....
            .....
</el-table>
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及代码

codepen.io/lozvoe/pen/…