表格分页多选默认回显实现
element的表格可以使用 row-key
和 reserve-selection
来实现多选翻页回显,但是在使用过程中却出现了,翻页之后,翻页保存的数据丢失问题。
复现前准备
首先是使用 el-table
和 el-pagination
搭建好基本的页面,包括获取表格数据事件,翻页事件以及表格的 selection-change
、row-key
、reserve-selection
和 ref
这些东西。
页面模板
<el-table
:data="list"
:row-key="getRowKey"
@selection-change="onSelectionChange"
ref="multipleTable"
>
<el-table-column type="selection" width="55" :reserve-selection="true"></el-table-column>
<el-table-column label="姓名" prop="name"></el-table-column>
<el-table-column label="sysId" prop="sysId"></el-table-column>
</el-table>
<el-pagination :current-page.sync="currentPage" @current-change="getTableData" :total="200"></el-pagination>
然后是表格(假)数据获取(翻页事件)、selection-change
事件、getRowKey
事件的实现。
获取表格(假)数据
// 获取表格数据
getTableData() {
const list = []
for (let i = 0; i < 10; i++) {
list.push({
sysId: this.currentPage + '' + i,
name: `用户-${this.currentPage + '' + i}`
})
}
this.list = list
// 勾选回显
this.$nextTick(() => {
this.tableEcho()
})
}
selection-change事件
根据官方文档,这个事件接收一个 selection
参数,该参数是一个数组,数组中存放着表格中被勾选的行的数据,如果使用了 reserve-selection
的话,那么即使翻页了重新勾选,这个 selection
中也会保存着之前勾选的数据。
举个例子来说,假如我在第一页,勾选了ABC3行数据,然后在第二页勾选了DE2行数据,那么当我们勾选E这一行的时候 selection
参数中是存在5个元素的,就是ABCDE这5个。
根据上面的描述,我们只需要在 selection-change
事件中,将 selection
参数赋值给一个变量就可以拿到分页表格所勾选的全部数据了。
因此这个 selection-change
的逻辑非常简单,只需要做简单的赋值操作
onSelectionChange(selection) {
this.selection = selection
}
getRowKey方法
这个根据表格中的数据来确定返回的数据,主要是不要存在重复的就可以了,比如说上面的假数据中,sysId是肯定不会重复的,因此 getRowKey
方法中返回表格数据的 sysId
。
getRowKey(row) {
return row.sysId
}
tableEcho勾选回显方法
这个方法中调用表格实例的 toggleRowSelection
方法进行勾选回显。
tableEcho() {
const tableRef = this.$refs.multipleTable
const sysIds = this.selection.map(i => i.sysId)
this.list.forEach(i => {
if (sysIds.includes(i.sysId)) {
tableRef.toggleRowSelection(i, true)
}
})
}
(状态)变量定义
最后就是在 data
中定义几个状态,比如说表格数据 list
,当前页面 currentPage
,当前已选行 selection
,然后就可以开始复现了。
复现过程
首先分成两种情况:selection
状态不存在默认值(空数组)和存在默认值(非空数组)。
不存在默认值
当 selection
为空数组的时候,无论如何勾选,翻页,都可以正常使用。
存在默认值
当 selection
为非空数组的时候,问题就出现了,假设 selection
中存储的是第一页的第1/2行数据和第3页的第4/5条数据,也就是说我们希望表格的第一页和第三页存在默认勾选的数据,注意是默认勾选。
selection: [
{ "sysId": "11", "name": "用户-11" },
{ "sysId": "12", "name": "用户-12" },
{ "sysId": "33", "name": "用户-33" },
{ "sysId": "34", "name": "用户-34" },
{ "sysId": "35", "name": "用户-35" }
]
然后进入到页面,我们可以发现,表格的第一页确实把1/2行的数据勾选起来了,如下图
但是问题是,当我们翻到第3页的时候,发现4/5却并没有被勾选起来,如下图
通过Vue开发者工具可以看到 selection
状态变成了只保存了第一页的勾选行,而丢失了第三页的勾选行。
通过在 selection-change
事件中 debugger
找到了原因,当我们获取到第一页表格数据的时候,进行表格勾选回显,此时 selection
参数中只存在第一页中默认被勾选的两行,然后 selection
被赋值给了 this.selection
,进而导致 this.selection
中原本存在的第三页默认勾选的数据被抹掉了,所以当表格翻到第三页的时候,本来该被勾选的行却没被勾选。
思考
1. 多加一个默认值状态(废弃)
因为 selction
状态被 selection
参数给冲掉了,所以我就想着多定义一个 defaultSelection
状态,里面存放需要进行默认回显的数据,然后我们的 tableEcho
方法就要改成下面这样:
tableEcho() {
const tableRef = this.$refs.multipleTable
//============= 这里变啦 👇
const sysIds = this.defaultSelection.map(i => i.sysId)
this.list.forEach(i => {
if (sysIds.includes(i.sysId)) {
tableRef.toggleRowSelection(i, true)
}
})
}
后来发现不行,因为没有去改变 defaultSelection
的逻辑,就会导致假如我把某一行数据取消勾选了,但是翻页之后还是会被重新勾选回来。
2. 不使用selection-change事件
问题出现的本质原因是, 我把被勾选项这个东西交给了 el-table
组件自己维护,如果我不使用 selection-change
事件,而是使用 select
事件,自己来对 selection
状态进行维护,自己来控制 selection
状态中元素的增删,这不就可以解决了吗?
/**
* 表格复选框勾选时事件
* @param selection 当前勾选的数据
* @param row 当前被勾选的行数据
*/
onSelect(selection, row) {
const {sysId} = row
const index = this.selection.findIndex(i => i.sysId === sysId)
// 如果已经包含该项 说明本次是取消勾选
if (index > -1) {
this.selection.splice(index, 1)
} else {
// 否则,将已勾选的push进去
this.selection.push(row)
}
}
然后删掉 el-table
的 selection-change
事件,添加上 select
事件。
<el-table
:data="list"
:row-key="getRowKey"
style="width: 100%"
@select="onSelect"
@select-all="onSelectAll"
ref="multipleTable"
>
因为存在全选逻辑,所以全选这里也要加上事件 onSelectAll
,全选事件只有一个参数 selection
,表示当前表格所有勾选的数据,每次变化的时候,它并不会告诉我们本次操作是全选还是全不选。
但是我们可以通过对比 this.selection
状态和 selection
参数的长度来判断出本次操作是对当前页的全选还是全不选。
因为在执行 select-all
之前,必然有着 this.selection.length === selection.length
的关系,当进行全选操作时,就会有 selection.length > this.selection.length
,反之,则有 selection.length < this.selection.length
。
什么?你说假设某一页默认被全部勾选了呢?嘿嘿,el-table
还是挺靠谱的,假如某一页默认全勾选,那么它就只有全不选这个操作。所以上面的那个判断关系,还是靠谱的。
onSelectAll(selection) {
/**
* this.selection.length > selection.length
* 表示全不选操作
* 那么就要把存在于this.selection中
* 且不存在于selection中的元素从this.selection中删除
* */
if (this.selection.length > selection.length) {
const sysIds = selection.map(i => i.sysId)
this.selection = this.selection.filter(item => sysIds.includes(item.sysId))
}
/**
* this.selection.length < selection.length
* 表示全选操作
* 把存在于selection且不存在于this.selection的元素
* 添加到this.selection中
*/
else if (this.selection.length < selection.length) {
const sysIds = this.selection.map(i => i.sysId)
const unExist = selection.filter(i => !sysIds.includes(i.sysId))
this.selection.push(...unExist)
}
}
// ===ChatGPT 代码简化 ==感觉不对=有空分析一下=简化后好像没有对全选全不选的判断===
onSelectAll(selection) {
const sysIds = selection.map(i => i.sysId)
const exist = this.selection.filter(item => sysIds.includes(item.sysId))
const unExist = selection.filter(i => !sysIds.includes(i.sysId))
this.selection = exist.concat(unExist)
}
测试了一下,嘎嘎棒。
结论
假如表格不存在默认勾选这种需求,那么使用下面的这个方法进行回显是最方便的。
row-key + reserve-selection + @selection-change + ref
假如表格存在默认勾选回显,那么则应该使用下面这种方法来实现需求
row-key + reserve-selection + @select + @select-all + ref
posted on 2023-07-11 13:57 __makabaka 阅读(679) 评论(0) 编辑 收藏 举报