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(key: keyof T, pageSpread = true) {
// 初始化`selectionMap`,用来保存已经勾选的选项
const selectionMap: Map = 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, tableData: Array) => {
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) => {
if (!pageSpread) {
selectionMap.clear()
selection.forEach(row => {
selectionMap.set(row[key], row)
})
}
}
/**
* 获取所有已勾选的选项
* @returns 所有已勾选的选项
*/
const getSelection = () => {
const selection: Array = []
for (const value of selectionMap.values()) {
selection.push(value)
}
return selection
}
/**
* 获取所有已勾选选项中key属性对应的值
* @returns 所有已勾选选项中key属性对应的值
*/
const getKeyArray = () => {
const valueArray: Array = []
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, tableRef: InstanceType) => {
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 | undefined>
/**
* 表格多选类,可支持跨页
* 把选项中具有唯一值的属性`key`作为`Map`的`key`,已选选项作为`Map`的`value`,构建哈希表储存在`selectionMap`中
* 如果支持跨页,需要使用el-table的`@select`和`@select-all`事件,并在回调函数中执行对应的方法
* 如果不支持跨页,则仅需要使用el-table的`@selection-change`事件,并在回调函数中执行对应的方法
* 如果用户手动配置是否支持跨页,则需要三个事件同时使用
*/
export class TableMultiSelection {
private selectionMap: Map = 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, tableData: Array) {
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) {
if (!this.pageSpread) {
this.selectionMap.clear()
selection.forEach(row => {
this.selectionMap.set(row[this.key], row)
})
}
}
/**
* 获取所有已勾选的选项
* @returns 所有已勾选的选项
*/
getSelection() {
const selection: Array = []
for (const value of this.selectionMap.values()) {
selection.push(value)
}
return selection
}
/**
* 获取所有已勾选选项中key属性对应的值
* @returns 所有已勾选选项中key属性对应的值
*/
getKeyArray() {
const valueArray: Array = []
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) {
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
}
}