效果预览
实现思路
data中定义 selectedList 数组保存选中的数据
在页面初次渲染、翻页、切换每页数据数量等每次重新获取表格数据渲染表格时,都根据 selectedList 勾选表格中已经选中的行
切换单行勾选状态时,判断是选中还是取消选中,选中则增加选中项,取消选中则移除选中项。
切换全选和取消全选时,根据当前页选中行的数据进行更新,若选中行已在 selectedList 中则不再重复添加,否则添加,对于其他非选中行若已在selectedList 中,则从 selectedList 中移除。
技术难点
1. 不能使用 selection-change 的原因
selection-change 的参数为当前页选中的所有行,在每次重新获取数据渲染表格时(如翻页时),参数为一个空数组,会导致历史选中的数据被清空!
即便使用 :reserve-selection="true"
来保留历史选中记录也无法达到预期效果。
2. toggleRowSelection失效的原因解析和解决方案
toggleRowSelection失效通常为以下两种情况:
(1)表格数据发生变化,表格还没渲染完便执行了toggleRowSelection
解决方案 : 在 $nextTick 中执行 toggleRowSelection
// toggleRowSelection 需在$nextTick中使用! this.$nextTick(() => { this.$refs.multipleTable.toggleRowSelection(row); });
(2)toggleRowSelection的第一个参数不是表格源数据
即便数据的值完全一样也会失效,因为数据为引用类型,必须地址一样。
解决方案 :toggleRowSelection的第一个参数通过在表格数据中通过 find() 查找得到。
this.$nextTick(() => { this.$refs.multipleTable.toggleRowSelection( // 此处必须在 tableData 中查找对应的数据,否则 toggleRowSelection 会失效 this.tableData.find((row) => { return row[this.UID] === item[this.UID]; }), false ); });
完整范例代码
<template> <div class="mainBox"> <h3>已选择:</h3> <el-tag :key="item[UID]" v-for="(item, index) in selectedList" closable @close="removeItemByIndex(index, item)" > {{ item.name }} </el-tag> <el-table v-loading="loading" ref="multipleTable" :data="tableData" @select="selectChange" @select-all="selectAllChange" > <el-table-column type="selection" width="55" align="center"> </el-table-column> <el-table-column prop="ID" label="编号" align="center"> </el-table-column> <el-table-column prop="name" label="姓名" align="center"> </el-table-column> <el-table-column prop="age" label="年龄" align="center"> </el-table-column> </el-table> <el-row type="flex" class="pageBanner" justify="center"> <el-pagination background :total="total" :page-size="pageSize" @size-change="pageSizeChange" @current-change="currentPageChange" :current-page="currentPage" :page-sizes="[1, 2, 3]" layout="total, sizes, prev, pager, next, jumper" > </el-pagination> </el-row> </div> </template> <script> export default { data() { return { // 唯一标识符 UID: "ID", loading: false, total: 0, pageSize: 3, currentPage: 1, selectedList: [ { ID: 1, name: "王小虎", age: 10, }, ], tableData: [], }; }, mounted() { // 页面初始化时,首次加载数据 this.getData(this.currentPage, this.pageSize); }, methods: { // 单行前的勾选状态切换 selectChange(selectedRows, row) { // true为选中, 0或false为取消选中 let selected = selectedRows.length && selectedRows.indexOf(row) !== -1; if (selected) { this.addItem(row); } else { this.removeItem(row); } }, // 全选/取消全选 selectAllChange(selectedRows) { let selectedMarkList = this.selectedList.map((item) => item[this.UID]); // 当前页选中行的标记列表 let pageSelectedMarkList = Array.isArray(selectedRows) ? selectedRows.map((item) => item[this.UID]) : []; this.tableData.forEach((row) => { if (pageSelectedMarkList.includes(row[this.UID])) { if (!selectedMarkList.includes(row[this.UID])) { this.addItem(row); } } else if (selectedMarkList.includes(row[this.UID])) { this.removeItem(row); } }); }, // 切换每页显示条数 pageSizeChange(newPageSize) { this.pageSize = newPageSize; this.getData(this.currentPage, this.pageSize); }, // 切换页码--翻页 currentPageChange(newPage) { this.currentPage = newPage; this.getData(this.currentPage, this.pageSize); }, // 更新勾选标记 updateMark() { let selectedMarkList = this.selectedList.map((item) => item[this.UID]); this.tableData.forEach((row) => { if (selectedMarkList.includes(row[this.UID])) { // toggleRowSelection 需在$nextTick中使用! this.$nextTick(() => { this.$refs.multipleTable.toggleRowSelection(row); }); } }); }, // 模拟访问接口获取数据 getData(page, pageSize) { this.loading = true; setTimeout(() => { let data = [ { ID: 1, name: "王小虎", age: 10, }, { ID: 2, name: "张三", age: 20, }, { ID: 3, name: "李四", age: 30, }, { ID: 4, name: "何香", age: 18, }, { ID: 5, name: "刘刀", age: 27, }, { ID: 6, name: "关胜", age: 33, }, { ID: 7, name: "齐巧", age: 55, }, { ID: 8, name: "卢一方", age: 45, }, { ID: 9, name: "王兴海", age: 66, }, { ID: 10, name: "全德", age: 100, }, ]; this.total = data.length; let startIndex = pageSize * (page - 1); let endIndex = pageSize * page; this.tableData = data.slice(startIndex, endIndex); this.updateMark(); this.loading = false; }, 1000); }, // 新增选中项 addItem(item) { this.selectedList.push(item); }, // 移除选中项 removeItem(item) { for (let [index, itemTemp] of this.selectedList.entries()) { if (itemTemp[this.UID] === item[this.UID]) { this.removeItemByIndex(index); break; } } }, // 根据下标移除选中项 removeItemByIndex(index, item) { this.selectedList.splice(index, 1); // 若有item,则是点击标签上的关闭按钮,移除选中项 if (item) { this.$nextTick(() => { this.$refs.multipleTable.toggleRowSelection( // 此处必须在 tableData 中查找对应的数据,否则 toggleRowSelection 会失效 this.tableData.find((row) => { return row[this.UID] === item[this.UID]; }), false ); }); } }, }, }; </script> <style scoped> .mainBox { margin: 30px; } .el-tag { margin: 10px; } .pageBanner { margin: 10px; } </style>
化为己用
若你的唯一标识符不是 ID
,则修改 data() 中的UID 的值即可!
// 唯一标识符 UID: "ID",