前言
在前端开发中,数据表格的多选管理是一项常见的需求,例如在数据筛选、批量操作等场景下,如何正确管理选中项显得尤为重要。
在网络上搜索 el-table
勾选回显的解决方案时,千篇一律的都是分页回显,并没有数据过滤及重置操作后的数据勾选回显实现。
本文将基于 Vue 3 和 Element Plus,详细讲解如何实现一个支持查询、重置、分页,并且能够正确管理选中项的表格
预览
1. 功能实现
- 多选与单选管理:实现选中的数据维护,确保在分页或查询数据后,选中状态依然保持不变。
- 勾选回显:确保在切换分页或查询数据后,已选中的项依然能够正确回显。
2. 组件模板结构
<template>
<el-button @click="search">查询</el-button>
<el-button @click="reset">重置</el-button>
<div style="display: flex">
<div style="width: 50%;height: 500px">
<el-table :data="tableData" ref="tableRef" height="100%" @select="nodeSelect" @select-all="selectAll">
<el-table-column type="selection" width="55"/>
<el-table-column property="id" label="ID"/>
</el-table>
<el-pagination v-model:current-page="page" v-model:page-size="pageSize" @current-change="pageChange"
:total="total"></el-pagination>
</div>
<el-table :data="selectedList" height="500px" style="width: 50%">
<el-table-column type="selection" width="55"/>
<el-table-column property="id" label="ID"/>
<el-table-column label="操作">
<template #default="{row, $index}">
<el-button type="danger" link @click="remove(row,$index)">移除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
3. 核心逻辑实现
3.1 数据初始化
const tableData = ref([]);
const selectedList = ref([]);
const page = ref(1);
const tableRef = ref(null);
const pageSize = ref(10);
const total = ref(30);
let saveId = new Set(); // 记录选中的 ID
let staticData = [];
let basicData = Array.from({length: 30}, (_, i) => ({ id: i }));
数据初始化时,tableData
存储表格数据,selectedList
存储已选中的数据,saveId
用于跟踪选中的 ID,避免分页和查询数据时丢失选中项。
3.2 模拟查询与重置功能
function search() {
staticData = [{"id": 0}, {"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}, {"id": 6}, {"id": 7}, {"id": 8}, {"id": 29}, {"id": 10}, {"id": 11}, {"id": 12}, {"id": 13}, {"id": 25}];
total.value = staticData.length;
tableData.value = staticData;
pageChange();
setCheck();
}
function reset() {
staticData = basicData;
total.value = staticData.length;
tableData.value = staticData;
pageChange();
setCheck();
}
查询功能会筛选部分数据,重置功能则恢复所有数据。
3.3 模拟分页
function pageChange() {
tableData.value = [];
let count = page.value * pageSize.value;
let num = (page.value * pageSize.value) - pageSize.value;
for (let i = num; i < count; i++) {
if (staticData[i]) tableData.value.push(staticData[i]);
}
setCheck();
}
3.4 选中状态管理
function nodeSelect(selection, node) {
node.checked = !node.checked;
if (node.checked) {
saveId.add(node.id);
selectedList.value.push(node);
} else {
saveId.delete(node.id);
selectedList.value = selectedList.value.filter(item => item.id !== node.id);
}
}
3.5 全选功能
function selectAll(selection) {
let setData = new Set();
if (!selection.length) {
tableData.value.forEach(item => {
item.checked = false;
saveId.delete(item.id);
setData.add(item.id);
})
let arr = []
selectedList.value.forEach(item => {
if (!setData.has(item.id)) {
item.checked = true
arr.push(item);
}
})
selectedList.value = arr
return
}
setData = new Set(selectedList.value.map(item => item.id));
selection.forEach(item => {
item.checked = true;
saveId.add(item.id);
if (saveId.has(item.id) && !setData.has(item.id)) {
selectedList.value.push(item);
}
})
}
3.6 维护勾选回显
function setCheck() {
nextTick(() => {
tableData.value.forEach(item => {
if (saveId.has(item.id)) {
item.checked = true;
tableRef.value.toggleRowSelection(item, true);
}
});
});
}
setCheck()
的作用是在查询、重置或分页切换后,确保之前选中的数据仍然保持选中状态。
3.7 移除选中项
function remove(row, i) {
selectedList.value.splice(i, 1);
saveId.delete(row.id);
for (let item of tableData.value) {
if (item.id === row.id) {
saveId.delete(row.id);
tableRef.value.toggleRowSelection(item, false);
break;
}
}
}
4. 源码
<template>
<el-button @click="search">查询</el-button>
<el-button @click="reset">重置</el-button>
<div style="display: flex">
<div style="width: 50%;height: 500px">
<el-table :data="tableData" ref="tableRef" height="100%" @select="nodeSelect" @select-all="selectAll">
<el-table-column type="selection" width="55"/>
<el-table-column property="id" label="ID"/>
</el-table>
<el-pagination v-model:current-page="page" v-model:page-size="pageSize" @current-change="pageChange"
:total="total"></el-pagination>
</div>
<el-table :data="selectedList" height="500px" style="width: 50%">
<el-table-column type="selection" width="55"/>
<el-table-column property="id" label="ID"/>
<el-table-column label="操作">
<template #default="{row, $index}">
<el-button type="danger" link @click="remove(row,$index)">移除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import {nextTick, ref} from "vue";
const tableData = ref([]) // 表格数据
const selectedList = ref([]); // 选中列表数据
const page = ref(1);
const tableRef = ref(null);
const pageSize = ref(10);
const total = ref(30);
let saveId = new Set(); // 保存选中 ID 的集合
let staticData = [] // 静态数据,用于存储查询或重置后的数据
let basicData = [{"id": 0}, {"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}, {"id": 6}, {"id": 7}, {"id": 8}, {"id": 9}, {"id": 10}, {"id": 11}, {"id": 12}, {"id": 13}, {"id": 14}, {"id": 15}, {"id": 16}, {"id": 17}, {"id": 18}, {"id": 19}, {"id": 20}, {"id": 21}, {"id": 22}, {"id": 23}, {"id": 24}, {"id": 25}, {"id": 26}, {"id": 27}, {"id": 28}, {"id": 29}]
reset()
/**
* 切换节点的选中状态
*
* @param selection 选中状态管理工具
* @param node 节点对象
*/
function nodeSelect(selection, node) {
node.checked = !node.checked;
if (node.checked) {
saveId.add(node.id);
selectedList.value.push(node);
} else {
let arr = [];
saveId.delete(node.id);
selectedList.value.forEach(item => {
if (item.id !== node.id) {
saveId.add(item.id);
arr.push(item);
item.checked = true;
} else {
item.checked = false;
}
});
selectedList.value = arr;
}
}
/**
* 全选函数
*/
function selectAll(selection) {
let setData = new Set();
if (!selection.length) {
tableData.value.forEach(item => {
item.checked = false;
saveId.delete(item.id);
setData.add(item.id);
})
let arr = []
selectedList.value.forEach(item => {
if (!setData.has(item.id)) {
item.checked = true
arr.push(item);
}
})
selectedList.value = arr
return
}
setData = new Set(selectedList.value.map(item => item.id));
selection.forEach(item => {
item.checked = true;
saveId.add(item.id);
if (saveId.has(item.id) && !setData.has(item.id)) {
selectedList.value.push(item);
}
})
}
/**
* 模拟查询
**/
function search() {
staticData = [
{"id": 0},
{"id": 1},
{"id": 2},
{"id": 3},
{"id": 4},
{"id": 5},
{"id": 6},
{"id": 7},
{"id": 8},
{"id": 29},
{"id": 10},
{"id": 11},
{"id": 12},
{"id": 13},
{"id": 25}
]
total.value = staticData.length;
tableData.value = staticData
pageChange()
setCheck()
}
/**
* 模拟重置数据,重新渲染表格
**/
function reset() {
staticData = basicData
total.value = staticData.length;
tableData.value = staticData
pageChange()
setCheck()
}
/**
* 模拟分页
**/
function pageChange() {
tableData.value = [];
let count = page.value * pageSize.value;
let num = (page.value * pageSize.value) - pageSize.value;
for (let i = num; i < count; i++) {
if (staticData[i]) tableData.value.push(staticData[i])
}
setCheck()
}
/**
* 设置选中项
*
* 将符合条件的数据设置为选中状态。
*/
function setCheck() {
nextTick(() => {
tableData.value.forEach(item => {
if (item && saveId.has(item.id)) {
item.checked = true;
tableRef.value.toggleRowSelection(item, true);
}
})
})
}
/**
* 从选中列表中移除指定行
* @param row 要移除的行对象
* @param i 要移除的行在选中列表中的索引
*/
function remove(row, i) {
selectedList.value.splice(i, 1);
saveId.delete(row.id);
for (let item of tableData.value) {
if (item.id === row.id) {
saveId.delete(row.id);
tableRef.value.toggleRowSelection(item, false);
break;
}
}
}
</script>
<style scoped>
</style>
5. 总结
本文介绍了如何实现一个支持分页、查询、重置、全选、单选回显勾选功能。核心难点在于如何正确管理选中项,使其在查询后仍然保持状态。希望本文对你有所帮助!