vue+elementui el-table,解决无论如何翻页,之前页码勾选过的数据依然是选中状态(表格翻页数据持久化)
<template> <div class="persistent-table-container"> <div class="bg-white rounded-lg shadow-md p-6 mb-6"> <!-- 接口返回的数据 --> <div> <el-table ref="tableRef" :data="topList" border stripe highlight-current-row :row-key="getRowKey" class="w-full"> <el-table-column prop="id" label="ID" width="80"></el-table-column> <el-table-column prop="name" label="姓名" width="120"></el-table-column> <el-table-column prop="age" label="年龄" width="80"></el-table-column> <el-table-column prop="gender" label="性别" width="80"> <template slot-scope="scope"> <span v-if="scope.row.gender === 1">男</span> <span v-else>女</span> </template> </el-table-column> <el-table-column prop="address" label="地址"></el-table-column> </el-table> </div> <div style="width:100%;height:20px;background:#ccc"></div> <!-- 下边进行操作改变的数据 --> <div class="overflow-x-auto"> <el-table ref="sourceTableRef" :data="currentTableData" border stripe highlight-current-row @select="onTableSelect" @selection-change="handleSelectionChange" :row-key="getRowKey" class="w-full"> <el-table-column type="selection" width="55" :reserve-selection="true"></el-table-column> <el-table-column prop="id" label="ID" width="80"></el-table-column> <el-table-column prop="name" label="姓名" width="120"></el-table-column> <el-table-column prop="age" label="年龄" width="80"></el-table-column> <el-table-column prop="gender" label="性别" width="80"> <template slot-scope="scope"> <span v-if="scope.row.gender === 1">男</span> <span v-else>女</span> </template> </el-table-column> <el-table-column prop="address" label="地址"></el-table-column> </el-table> </div> <div class="flex justify-between items-center mt-4"> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage" :page-sizes="[10, 20, 30]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total"> </el-pagination> </div> <div class="flex items-center gap-2"> <span class="text-gray-600">当前选择项数:</span> <el-badge :value="alreadyData.length" class="ml-2"> <el-button size="mini" type="info">查看</el-button> </el-badge> </div> <div class="flex flex-col md:flex-row md:items-center justify-between mb-4 gap-4"> <div class="flex items-center gap-4"> <el-button type="success" icon="el-icon-upload" @click="submitSelection">提交选择</el-button> </div> </div> </div> </div> </template> <script> export default { name: 'PersistentTable', data() { return { // 表格数据 tableData: [], // 当前页数据 currentTableData: [], // 每页条数 pageSize: 10, // 当前页码 currentPage: 1, // 总记录数 total: 0, // 已选择的完整数据对象 selectedItems: [], // 模拟API请求延迟 apiDelay: 500, topList:[ { "id": 3, "name": "李四", "age": 56, "gender": 0, "address": "南京市鼓楼区新街口" }, { "id": 4, "name": "吴十", "age": 30, "gender": 1, "address": "成都市武侯区天府广场" }, { "id": 15, "name": "赵六", "age": 46, "gender": 0, "address": "武汉市武昌区黄鹤楼" }, { "id": 27, "name": "王五", "age": 51, "gender": 1, "address": "武汉市武昌区黄鹤楼" } ], alreadyData:[] } }, mounted() { this.fetchData(); this.getAlreadyList() }, methods: { getAlreadyList(){ this.alreadyData = JSON.parse(JSON.stringify(this.topList)) }, // 获取表格数据 fetchData() { console.log(111,'-=-='); // 显示加载状态 if (this.$refs.tableRef) { this.$refs.tableRef.loading = true; } // 模拟API请求延迟 setTimeout(() => { // 如果是第一页,初始化表格数据 if (this.currentPage === 1) { this.tableData = this.generateMockData(100); this.total = this.tableData.length; } // 计算当前页数据 const start = (this.currentPage - 1) * this.pageSize; const end = start + this.pageSize; this.currentTableData = this.tableData.slice(start, end); this.currentTableData.forEach(item=>{ this.topList.forEach(type=>{ if(item.id==type.id){ this.$refs.sourceTableRef.toggleRowSelection(item, true); } }) }) // 隐藏加载状态 if (this.$refs.tableRef) { this.$refs.tableRef.loading = false; } }, this.apiDelay); }, // 生成模拟数据 generateMockData(count) { const names = ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十']; const genders = [1, 0]; const addresses = [ '北京市朝阳区建国路88号', '上海市浦东新区张江高科技园区', '广州市天河区珠江新城', '深圳市南山区科技园', '杭州市西湖区西溪湿地', '南京市鼓楼区新街口', '成都市武侯区天府广场', '武汉市武昌区黄鹤楼' ]; return Array.from({ length: count }, (_, i) => ({ id: i + 1, name: names[Math.floor(Math.random() * names.length)], age: Math.floor(Math.random() * 40) + 20, gender: genders[Math.floor(Math.random() * genders.length)], address: addresses[Math.floor(Math.random() * addresses.length)] })); }, // 设置行唯一标识 getRowKey(row) { return row.id; }, //复选框改变会走这个方法, //两个参数,rows:改变后剩余的已勾选的元素 //row:当前操作的行数据 onTableSelect(rows, row) { //根据剩余的已勾选元素中是否存在当前操作行的数据判断,如果包含则是选中操作,否则就是取消选中。就是判断是勾选还是取消勾选 let selected = rows.length && rows.indexOf(row) !== -1; //如果是选中操作,把选中行数据加入上方table //如果是取消操作,判断上方table中存在当前id,删除该元素 if(selected){//勾选 this.alreadyData.push(row); }else{//取消 let index = this.alreadyData.findIndex(item => item.id === row.id);//获取当前操作行,在alreadyData数据中的索引值 if(index!=-1){//如果值不是-1,说明他存在alreadyData数据中,并给删除掉 this.alreadyData.splice(index, 1); } } }, // 处理选择变化 handleSelectionChange(selection) { // console.log(selection,'====='); // // 更新已选择的完整数据对象 // this.selectedItems = [...selection]; // let qzArr = Array.from(new Set(this.selectedItems.map(item => item.id))).map(id => { // return this.selectedItems.find(item => item.id === id); // }) // // 打印当前选择项 // console.log('去重前选择项:', this.selectedItems); // console.log('去重前选择项ID:', this.selectedItems.map(item => item.id)); // console.log('======================================================='); // console.log('去重后的项',qzArr); // console.log('去重后的项ID',qzArr.map(item => item.id)); // console.log('======================================================='); // console.log('最初上边数据',this.topList); }, // 处理每页条数变化 handleSizeChange(newSize) { this.pageSize = newSize; this.currentPage = 1; this.fetchData(); }, // 处理页码变化 handleCurrentChange(newPage) { this.currentPage = newPage; this.fetchData(); }, // 提交选择 submitSelection() { console.log('要提交的数据',this.alreadyData); }, } } </script> <style scoped> .persistent-table-container { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #2c3e50; max-width: 1200px; margin: 0 auto; padding: 20px; } pre { font-family: Consolas, Monaco, 'Andale Mono', monospace; white-space: pre-wrap; word-break: break-all; } </style>
附加一个:根据上方表格数据,下方表格进行实时动态勾选或取消勾选
<template> <div class="container"> <h3>上方表格 (ID数据源)</h3> <el-table ref="upperTableRef" :data="upperTableData" stripe border :row-key="row => row.id"> <el-table-column prop="id" label="ID" width="100" align="center"></el-table-column> <el-table-column prop="name" label="姓名" width="120"></el-table-column> <el-table-column prop="age" label="年龄" width="80" align="center"></el-table-column> <el-table-column label="操作" width="120"> <template #default="scope"> <el-button size="mini" type="danger" @click="removeRow(scope.row.id)"> 删除 </el-button> </template> </el-table-column> </el-table> <div class="divider"></div> <h3>下方表格 (自动勾选匹配ID)</h3> <el-table ref="lowerTableRef" :data="lowerTableData" stripe border :row-key="row => row.id"> <el-table-column type="selection" width="55" align="center"></el-table-column> <el-table-column prop="id" label="ID" width="100" align="center"></el-table-column> <el-table-column prop="name" label="姓名" width="120"></el-table-column> <el-table-column prop="age" label="年龄" width="80" align="center"></el-table-column> <el-table-column prop="status" label="状态" width="100" align="center"></el-table-column> </el-table> <div class="stats" v-if="selectedCount > 0"> <el-tag type="success" effect="plain"> 下方表格已自动勾选 {{ selectedCount }} 条匹配数据 </el-tag> </div> </div> </template> <script> export default { data() { return { // 上方表格数据 upperTableData: [ { id: 2, name: '李四', age: 30 }, { id: 3, name: '王五', age: 22 }, { id: 4, name: '赵六', age: 35 }, { id: 5, name: '孙七', age: 28 } ], // 下方表格数据 lowerTableData: [ { id: 1, name: '张三', age: 25, status: '未匹配' }, { id: 2, name: '李四', age: 30, status: '匹配中' }, { id: 3, name: '王五', age: 22, status: '匹配中' }, { id: 4, name: '赵六', age: 35, status: '匹配中' }, { id: 5, name: '孙七', age: 28, status: '匹配中' }, { id: 6, name: '周八', age: 40, status: '未匹配' } ] }; }, computed: { // 计算当前匹配并被勾选的行数 selectedCount() { return this.lowerTableData.filter(row => this.upperTableData.some(upperRow => upperRow.id === row.id) ).length; } }, created() { // 初始化时同步一次勾选状态 this.$nextTick(() => { this.syncLowerTableSelection(); }); }, methods: { // 删除上方表格行 removeRow(id) { // 从上方表格数据中移除 const index = this.upperTableData.findIndex(row => row.id === id); if (index !== -1) { this.upperTableData.splice(index, 1); // 同步下方表格的勾选状态 this.syncLowerTableSelection(); this.$message({ type: 'success', message: `已删除ID为 ${id} 的数据` }); } }, // 同步下方表格的勾选状态 syncLowerTableSelection() { // 确保表格DOM已更新 this.$nextTick(() => { // 清空下方表格的所有选中状态 if (this.$refs.lowerTableRef) { this.$refs.lowerTableRef.clearSelection(); // 遍历下方表格数据,勾选与上方表格ID匹配的行 this.lowerTableData.forEach(row => { if (this.upperTableData.some(upperRow => upperRow.id === row.id)) { this.$refs.lowerTableRef.toggleRowSelection(row, true); } }); // 更新状态文本 this.updateStatusTexts(); } }); }, // 更新状态文本 updateStatusTexts() { this.lowerTableData.forEach(row => { row.status = this.upperTableData.some(upperRow => upperRow.id === row.id) ? '匹配中' : '未匹配'; }); } } }; </script> <style scoped> .container { padding: 20px; max-width: 1200px; margin: 0 auto; } .divider { height: 20px; border-bottom: 1px solid #ebeef5; margin: 30px 0; } .stats { margin-top: 15px; text-align: center; } </style>
    是我吖~

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号