以下是纯Vue实现的表格多选方案(不依赖UI库),支持跨页选择和回显功能:
<template>
<div class="custom-table">
<!-- 表格主体 -->
<table>
<thead>
<tr>
<th>
<input
type="checkbox"
:checked="isAllChecked"
@change="toggleAllSelection"
>
</th>
<th>ID</th>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr v-for="item in currentPageData" :key="item.id">
<td>
<input
type="checkbox"
:checked="isSelected(item.id)"
@change="toggleSelection(item)"
>
</td>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
</tr>
</tbody>
</table>
<!-- 分页控件 -->
<div class="pagination">
<button
v-for="page in totalPages"
:key="page"
:class="{ active: currentPage === page }"
@click="currentPage = page"
>
{{ page }}
</button>
</div>
<!-- 已选展示 -->
<div class="selected-info">
已选ID: {{ selectedIds.join(', ') }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
// 原始数据
allData: [],
// 分页相关
currentPage: 1,
pageSize: 5,
// 选中数据
selectedItems: new Map(), // 使用Map存储保证顺序
}
},
computed: {
// 当前页数据
currentPageData() {
const start = (this.currentPage - 1) * this.pageSize
const end = start + this.pageSize
return this.allData.slice(start, end)
},
// 总页数
totalPages() {
return Math.ceil(this.allData.length / this.pageSize)
},
// 当前页是否全选
isAllChecked() {
return this.currentPageData.every(item =>
this.selectedItems.has(item.id)
)
},
// 已选ID数组
selectedIds() {
return Array.from(this.selectedItems.keys())
}
},
created() {
// 生成模拟数据
this.generateMockData(23)
// 模拟回显数据(实际从API获取)
this.$nextTick(() => {
this.setInitialSelection([2, 5, 9]) // 回显ID为2、5、9的数据
})
},
methods: {
// 生成模拟数据
generateMockData(count) {
for(let i = 1; i <= count; i++) {
this.allData.push({
id: i,
name: `User ${i}`,
age: 20 + (i % 10)
})
}
},
// 设置初始选中(回显)
setInitialSelection(ids) {
ids.forEach(id => {
const item = this.allData.find(d => d.id === id)
if(item) this.selectedItems.set(id, item)
})
},
// 切换单个选择
toggleSelection(item) {
if(this.selectedItems.has(item.id)) {
this.selectedItems.delete(item.id)
} else {
this.selectedItems.set(item.id, item)
}
},
// 切换全选
toggleAllSelection(e) {
const checked = e.target.checked
this.currentPageData.forEach(item => {
if(checked) {
this.selectedItems.set(item.id, item)
} else {
this.selectedItems.delete(item.id)
}
})
},
// 检查是否选中
isSelected(id) {
return this.selectedItems.has(id)
}
}
}
</script>
<style scoped>
.custom-table {
max-width: 800px;
margin: 20px auto;
font-family: Arial, sans-serif;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
th, td {
border: 1px solid #ddd;
padding: 12px;
text-align: left;
}
th {
background-color: #f5f5f5;
}
tr:hover {
background-color: #f9f9f9;
}
.pagination {
display: flex;
gap: 8px;
margin-bottom: 20px;
}
.pagination button {
padding: 6px 12px;
border: 1px solid #ddd;
background: white;
cursor: pointer;
border-radius: 4px;
}
.pagination button.active {
background: #409eff;
color: white;
border-color: #409eff;
}
.selected-info {
padding: 12px;
background: #f5f5f5;
border-radius: 4px;
}
</style>
核心实现逻辑:
数据结构设计:
allData
:存储全部数据(模拟数据)selectedItems
:使用Map存储选中项,方便快速查找currentPageData
:计算属性获取当前页数据
跨页选择实现:
- 使用Map存储选中项,不受分页影响
- 切换页面时自动保留选中状态
- 通过
isSelected
方法检查当前行是否选中
回显功能:
- 提供
setInitialSelection
方法初始化选中项 - 支持传入ID数组自动匹配数据项
- 提供
全选功能:
- 当前页全选/取消全选
- 自动同步到全局选中状态
- 智能显示全选复选框状态
性能优化:
- 使用Map数据结构提升查找效率
- 计算属性缓存计算结果
- 虚拟滚动友好(可扩展)
功能扩展建议:
分页优化:
// 在methods中添加 goToPage(page) { if(page < 1 || page > this.totalPages) return this.currentPage = page } // 在模板中添加 <button @click="goToPage(currentPage - 1)">上一页</button> <button @click="goToPage(currentPage + 1)">下一页</button>
多选操作增强:
// 清空选择 clearSelection() { this.selectedItems.clear() } // 批量删除 deleteSelected() { this.allData = this.allData.filter( item => !this.selectedItems.has(item.id) this.clearSelection() }
数据持久化:
// 本地存储示例 watch: { selectedItems: { handler(newVal) { localStorage.setItem('selectedItems', JSON.stringify([...newVal])) }, deep: true } }
性能增强(大数据量):
// 使用虚拟滚动 // 安装vue-virtual-scroller import { RecycleScroller } from 'vue-virtual-scroller' // 替换tbody部分 <RecycleScroller class="scroller" :items="currentPageData" :item-size="48" key-field="id" > <template #default="{ item }"> <tr> <!-- 原有td内容 --> </tr> </template> </RecycleScroller>
使用说明:
- 通过
setInitialSelection
方法初始化回显数据 - 获取选中数据:
Array.from(this.selectedItems.values())
- 修改
pageSize
可调整每页显示数量 - 样式可根据需求自定义修改
这个实现方案具有以下特点:
- 零依赖,纯Vue实现
- 完整的分页选择逻辑
- 高性能的选中状态管理
- 灵活的回显机制
- 易于扩展的自定义样式
- 支持大数据量的虚拟滚动(需额外配置)