element-plus的多选表格支持跨页,只需要在el-table设置row-key属性,然后在type="selection"的列设置:reserve-selection="true"即可跨页保存选项。

那么,如果想要自己实现,该如何做呢?

基本思路:使用es6的map储存已经勾选的变量,当翻页、跳页或者分页规格改变的时候,利用table的toggleRowSelection方法将当前分页下存在于map的选项勾选上。

代码如下:

import { ElTable } from 'element-plus'

/**
 * 表格多选,可支持跨页
 * 把选项中具有唯一值的属性`key`作为`Map`的`key`,已选选项作为`Map`的`value`,构建哈希表储存在`selectionMap`中
 * 如果支持跨页,需要使用el-table的`@select`和`@select-all`事件,
 * 如果不支持跨页,则仅需要使用el-table的`@selection-change`事件,
 * 并在回调函数中执行对应的方法即可
 * @param {keyof T} key 每个选项中具有唯一值的属性`key`
 * @param {boolean} pageSpread 是否支持跨页,默认支持
 * @returns 返回`selectionMap`的属性和操作`selectionMap`的方法,避免直接操作`selectionMap`
 */
export function tableMultiSelection<T>(key: keyof T, pageSpread = true) {

  // 初始化`selectionMap`,用来保存已经勾选的选项
  const selectionMap: Map<T[keyof T], T> = new Map()

  /**
   * 当用户手动勾选数据行的 Checkbox 时执行此方法
   * @param row 当前选中或取消选中的选项
   * @returns 
   */
  const onSelect = (row: T) => {
    if (!pageSpread) return
    // 如果selectionMap有row,说明是用户取消勾选,否则是用户勾选
    if (selectionMap.has(row[key])) {
      selectionMap.delete(row[key])
    } else {
      selectionMap.set(row[key], row)
    }
  }

  /**
   * 当用户手动勾选全选 Checkbox 时执行此方法
   * @param selection 当前页所有的选中的选项
   * @param tableData 当前页面表格中的所有选项
   * @returns 
   */
  const onSelectAll = (selection: Array<T>, tableData: Array<T>) => {
    if (!pageSpread) return
    if (selection.length > 0) {
      selection.forEach(row => {
        selectionMap.set(row[key], row)
      })
    } else {
      tableData.forEach(row => {
        selectionMap.delete(row[key])
      })
    }
  }

  /**
   * 当选择项发生变化时执行此方法
   * @param selection 选中的选项
   */
  const handleSelectionChange = (selection: Array<T>) => {
    if (!pageSpread) {
      selectionMap.clear()
      selection.forEach(row => {
        selectionMap.set(row[key], row)
      })
    }
  }

  /**
   * 获取所有已勾选的选项
   * @returns 所有已勾选的选项
   */
  const getSelection = () => {
    const selection: Array<T> = []
    for (const value of selectionMap.values()) {
      selection.push(value)
    }
    return selection
  }

  /**
   * 获取所有已勾选选项中key属性对应的值
   * @returns 所有已勾选选项中key属性对应的值
   */
  const getKeyArray = () => {
    const valueArray: Array<T[keyof T]> = []
    for (const key of selectionMap.keys()) {
      valueArray.push(key)
    }
    return valueArray
  }

  /**
   * 获取`selectionMap`的长度
   * @returns `selectionMap`的长度
   */
  const getMapSize = () => {
    return selectionMap.size
  }

  /**
   * 清空`selectionMap`
   */
  const clear = () => {
    selectionMap.clear()
  }

  /**
   * 判断某个选项是否已勾选
   * @param row 
   * @returns 
   */
  const has = (row: T) => {
    return selectionMap.has(row[key])
  }

  /**
   * 删除某个选项
   * @param row 
   * @returns {boolean} 是否删除成功
   */
  const deleteSelection = (row: T) => {
    return selectionMap.delete(row[key])
  }

  /**
   * 翻页、跳页或者修改分页规格后,勾选当前分页下存在于`selectionMap`中的选项
   * @param tableData 
   * @param tableRef 
   */
  const checkSelection = (tableData: Array<T>, tableRef: InstanceType<typeof ElTable>) => {
    tableData.forEach(row => {
      if (selectionMap.has(row[key])) {
        tableRef!.toggleRowSelection(row, true)
      }
    })
  }

  /**
   * 手动配置是否可以跨页
   * @param isSpread 是否跨页
   */
  const setPageSpread = (isSpread: boolean) => {
    pageSpread = isSpread
  }

  return {
    onSelect,
    onSelectAll,
    handleSelectionChange,
    getSelection,
    getKeyArray,
    getMapSize,
    clear,
    has,
    deleteSelection,
    checkSelection,
    setPageSpread,
  }
}

class版本:

import { ElTable } from 'element-plus'
import { Ref } from 'vue'

type TableRef = Ref<InstanceType<typeof ElTable> | undefined>

/**
 * 表格多选类,可支持跨页
 * 把选项中具有唯一值的属性`key`作为`Map`的`key`,已选选项作为`Map`的`value`,构建哈希表储存在`selectionMap`中
 * 如果支持跨页,需要使用el-table的`@select`和`@select-all`事件,并在回调函数中执行对应的方法
 * 如果不支持跨页,则仅需要使用el-table的`@selection-change`事件,并在回调函数中执行对应的方法
 * 如果用户手动配置是否支持跨页,则需要三个事件同时使用
 */
export class TableMultiSelection<T extends object> {

  private selectionMap: Map<T[keyof T], T> = new Map()
  private key: keyof T
  private pageSpread: boolean
  tableRef: TableRef

  /**
   * 构造函数
   * @param {keyof T} key 每个选项中具有唯一值的属性`key`
   * @param {TableRef} tableRef `table`元素代理的引用
   * @param {boolean} pageSpread 是否支持跨页,默认支持
   */
  constructor(key: keyof T, tableRef: TableRef, pageSpread = true) {
    this.key = key
    this.tableRef = tableRef
    this.pageSpread = pageSpread
  }

  /**
   * 当用户手动勾选数据行的 Checkbox 时执行此方法
   * @param row 当前选中或取消选中的选项
   * @returns 
   */
  onSelect(row: T) {
    if (!this.pageSpread) return
    // 如果selectionMap中有row,说明是用户取消勾选,否则是用户勾选
    if (this.selectionMap.has(row[this.key])) {
      this.selectionMap.delete(row[this.key])
    } else {
      this.selectionMap.set(row[this.key], row)
    }
  }

  /**
   * 当用户手动勾选全选 Checkbox 时执行此方法
   * @param selection 当前页所有的选中的选项
   * @param tableData 当前页面表格中的所有选项
   * @returns 
   */
  onSelectAll(selection: Array<T>, tableData: Array<T>) {
    if (!this.pageSpread) return
    if (selection.length > 0) {
      selection.forEach(row => {
        this.selectionMap.set(row[this.key], row)
      })
    } else {
      tableData.forEach(row => {
        this.selectionMap.delete(row[this.key])
      })
    }
  }

  /**
   * 当选择项发生变化时执行此方法
   * @param selection 选中的选项
   */
  handleSelectionChange (selection: Array<T>) {
    if (!this.pageSpread) {
      this.selectionMap.clear()
      selection.forEach(row => {
        this.selectionMap.set(row[this.key], row)
      })
    }
  }

  /**
   * 获取所有已勾选的选项
   * @returns 所有已勾选的选项
   */
  getSelection() {
    const selection: Array<T> = []
    for (const value of this.selectionMap.values()) {
      selection.push(value)
    }
    return selection
  }

  /**
   * 获取所有已勾选选项中key属性对应的值
   * @returns 所有已勾选选项中key属性对应的值
   */
  getKeyArray() {
    const valueArray: Array<T[keyof T]> = []
    for (const key of this.selectionMap.keys()) {
      valueArray.push(key)
    }
    return valueArray
  }

  /**
   * 获取`selectionMap`的长度
   * @returns `selectionMap`的长度
   */
  getMapSize() {
    return this.selectionMap.size
  }

  /**
   * 清空`selectionMap`
   */
  clear() {
    this.selectionMap.clear()
  }

  /**
   * 判断某个选项是否已勾选
   * @param row 
   * @returns 
   */
  has(row: T) {
    return this.selectionMap.has(row[this.key])
  }

  /**
   * 删除某个选项
   * @param row 
   * @returns {boolean} 是否删除成功
   */
  deleteSelection(row: T) {
    return this.selectionMap.delete(row[this.key])
  }

  /**
   * 清空选项
   */
  clearSelection() {
    this.clear()
    this.tableRef.value!.clearSelection()
  }

  /**
   * 翻页、跳页或者修改分页规格后,勾选当前分页下存在于`selectionMap`中的选项
   * @param tableData 
   */
  checkSelection(tableData: Array<T>) {
    tableData.forEach(row => {
      if (this.selectionMap.has(row[this.key])) {
        this.tableRef.value!.toggleRowSelection(row, true)
      }
    })
  }

  /**
   * 手动配置是否可以跨页
   * @param isSpread 是否跨页
   */
  setPageSpread(isSpread: boolean) {
    this.clearSelection()
    this.pageSpread = isSpread
  }
}

Logo

前往低代码交流专区

更多推荐