使用el-table实现shift多选组件

832 阅读1分钟

动画2.gif 借助elementUI的table组件开发表格多选功能组件。

需要考虑的问题:

  1. 监听按键,如shift键,keyCode = 16。考虑elementUI的选择事件是否返回了鼠标键盘操作的事件,没有的话只能自己监听,并销毁。
  2. 不影响原有elementUI的功能属性使用。使用attrsattrs,listeners。
  3. 考虑表格从上至下选择,从下至上选择。
  • template部分
<template>
  <el-table
    ref="mainTable"
    :data="tableData"
    v-bind="$attrs"
    v-on="$listeners"
    @selection-change="handleSelectChange"
    @select="handleSelectionChange"
    @select-all="handleSelectionChange"
  >
    <slot />
  </el-table>
</template>
  • js部分

接收外部传入的data数据,循环为每一条数据加上唯一的有序标记_index

  props: {
    data: {
      type: Array,
      required: true
    }
  },
  watch: {
    data(val) {
      this.addAttrIndex(val)
    }
  },
  addAttrIndex(list) {
    if (list.length) {
      for (let i = 0; i < list.length; i++) {
        Object.defineProperty(list[i], '_index', { // 添加index属性 用于shift多选
          value: i,
          writable: true,
          enumerable: false
        })
      }
    }
    this.tableData = list
  }

监听键盘事件并及时销毁。

  mounted() {
    addEventListener('keydown', this.keyDown, false)
    addEventListener('keyup', this.keyUp, false)
  },
  beforeDestroy() {
    removeEventListener('keydown', this.keyDown)
    removeEventListener('keyup', this.keyUp)
  },
  keyDown({ keyCode }) { if (keyCode === 16) { this.shiftDown = true } },
  keyUp({ keyCode }) { if (keyCode === 16) { this.shiftDown = false } },

重新定义选择的事件,包括@selection-change @select @select-all

  1. 选择数据改变事件@selection-change
handleSelectChange(selection) {
  this.selection = selection
  this.$emit('selection-change', selection)
}
  1. 选择某行数据事件及全部选择事件 @select@select-all
    handleSelectionChange(val, row) {
      const { shiftDown, preClickIndex } = this
​
      const checked = val.includes(row)
      // 选中+shift键+preClickIndex存在
      if (checked && shiftDown && preClickIndex > -1) {
        val = this.shiftMultiSel(preClickIndex, row._index)
        this.$nextTick(() => {
          for (let i = 0; i < val.length; i++) {
            this.$refs.mainTable.toggleRowSelection(val[i], true)
          }
        })
      }
      // 没有按shift时 记录位置
      this.preClickIndex = (row && checked && !shiftDown) ? row._index : -1
​
      this.$emit('select', val, row)
    },
    shiftMultiSel(preIndex, rowIndex) { // shift多选  返回应该选择rows
      const { tableData } = this
​
      const top = Math.min(preIndex, rowIndex)
      const bottom = Math.max(preIndex, rowIndex)
​
      return Array.from(new Set([...this.selection,
        ...(tableData.slice(top, bottom + 1))]))
    }

大概思路就是这样,代码还是比较简单的!