el-table一键全选,分页的完美支持
问题背景
现在有个需求,一个表格有若干条数据(假设数量大于20,每页10条,保证有2个以上分页即可)。
现在需要在表格上方加个全部选择
的按钮,点击全部选择
按钮时,可以把表格的复选框全部勾选,切换分页后依然是勾选状态,那么怎么实现呢?示意图如下:
尝试解决
我们平时做表格的勾选时,一般都用selection-change
方法。
假设我们有个接口getAllTableIds
返回数据的全部id,那么我们尝试以下方法来实现上述需求:
javascript
<el-button type="primary" plain size="mini" @click="handleSelectAll">全部选中</el-button>
<el-table
ref="tableRef"
:data="tableData"
@selection-change="handleSelectionChange"
:row-key="row => row.id"
>
<el-table-column type="selection" reserve-selection label="序号" />
<el-table-column label="编号" prop="code" />
</el-table>
export default {
methods: {
/** 多选框选中操作 */
handleSelectionChange(selection) {
this.ids = selection.map((item) => item.id);
},
// 全部选中
handleSelectAll() {
getAllTableIds().then(res => {
this.ids = res.data
this.setSelectedCheckbox()
})
},
// 设置按勾选框选中
setSelectedCheckbox() {
this.$nextTick(() => {
if (this.ids.length > 0) {
this.tableData.forEach((item) => {
if ( this.ids.includes(item.id) ) {
this.$refs.tableRef.toggleRowSelection(item, true);
}
});
}
})
},
}
}
存在问题
你这样写了之后,感觉还不错,点击全部选中
按钮,也确实全都勾选了,就像上图一样,但是当你切换到第二页时,你就傻眼了,咋没勾选上呢?
问题分析
上面我们的思路主要分为以下几个步骤:
-
点击按钮,从接口处获取全部id列表,并保存到ids数组变量
-
遍历当前页的数据,如果ids中存在该id,那么就把当前行设置为勾选状态
-
切换分页时也调用
setSelectedCheckbox
方法 -
傻眼了
其实,逻辑都没有错,错的是没用对方法,就是上面提到的selection-change
方法,如果你对该方法的函数handleSelectionChange
打印一下,你会发现该方法执行了10次(因为每页10条数据)
因为你在循环中执行勾选:javascriptthis.$refs.tableRef.toggleRowSelection(item, true);
就不断地触发
handleSelectionChange
方法,这也导致上面给ids
赋值全部id的集合,也会变为当前页的集合,也就导致当你切换分页时,第二页不会勾选的原因。
解决方案
el-table
文档中还有这两种方法
既然循环勾选的时候会触发selection-change
的方法,那么我们不用这个方法不就好了吗。
监听表格变化,可以用select
和select-all
两种方法的结合;因为勾选状态无非就是勾选单行
和勾选当前页
两种嘛!
改进思路如下
- 点击按钮,从接口处获取全部id列表,并保存到ids数组变量
- 遍历当前页的数据,如果ids中存在该id,那么就把当前行设置为勾选状态
- 切换分页时也调用
setSelectedCheckbox
方法 - 单行勾选变化
- 选中:把该行id值push进
ids
数组,并去重(防止以外情况) - 取消勾选:把该行id值从
ids
数组中去除
- 选中:把该行id值push进
- 当前页勾选变化
- 选中:把当前页的id值push进
ids
数组,并去重(防止以外情况) - 取消勾选:把当前页的id值从
ids
数组中去除
- 选中:把当前页的id值push进
这样就不会影响ids的值了!
具体代码实现如下
javascript
<el-button type="primary" plain size="mini" @click="handleSelectAll">全部选中</el-button>
<el-table
ref="tableRef"
:data="tableData"
@select="handleSelectRow"
@select-all="handleSelectAllRow"
:row-key="row => row.id"
>
<el-table-column type="selection" reserve-selection label="序号" />
<el-table-column label="编号" prop="code" />
</el-table>
export default {
methods: {
/** 多选框选中操作 */
handleSelectionChange(selection) {
this.ids = selection.map((item) => item.id);
},
// 选择某行
handleSelectRow(selection, row) {
const id = row.id
if(this.ids.includes(id)) {
this.ids = this.ids.filter(item => item !== id)
} else {
this.ids.push(id)
}
},
// 选择当前页
handleSelectAllRow(selection) {
// 如果全部勾选
if(selection.length > 0) {
const ids = selection.map((item) => item.id);
this.ids = Array.from(new Set([...this.ids,...ids]))
} else {
// 如果当前页取消勾选
const ids = this.tableData.map((item) => item.id);
this.ids = this.ids.filter(item => !ids.includes(item))
}
},
// 设置按勾选框选中
setSelectedCheckbox() {
this.$nextTick(() => {
if (this.ids.length > 0) {
this.tableData.forEach((item) => {
if ( this.ids.includes(item.id) ) {
this.$refs.tableRef.toggleRowSelection(item, true);
}
});
}
})
},
}
}
这样就能解决一键全选、且分页保留勾选状态的功能了!
别忘了,请求列表接口时也调用
setSelectedCheckbox
方法
如果有更好的解决办法,可在评论区讨论,谢谢。