业务场景
在后台管理系统开发中,经常会遇到动态渲染多个并列表格的复杂场景。
以某租房后台为例:

一个户型下可以添加多个「房间」,每个房间对应一张独立表格,表格内可配置租期、付款方式、月租金等参数。业务需要实现:
-
所有表格统一全选 、取消全选
-
每个表格支持单独手动勾选,互不干扰
-
精准记录「哪些表格处于选中状态」,用于后续批量赋值、批量删除
-
表格无表头、嵌套表单组件,贴合后台复杂配置页样式
今天分享一套零 Bug、完全贴合真实业务的多表格全选解决方案(Vue3 + TS + ElementPlus)。
原理分析
1、v-for 循环绑定同名 ref,通过下标 multipleTable.value[i] 可获取每一个表格实例,解决 ref 覆盖问题
2、Vue 是异步 DOM 更新,nextTick 保证在 DOM 渲染完成后再操作表格勾选 ,是功能生效的关键
3、ElementPlus 核心表格 API
-
toggleAllSelection():表格原生全选/反选方法 -
clearSelection():清空表格所有选中项 -
selection-change:表格勾选状态变化监听事件
核心完整源码
javascript
<template>
<div class="demo">
<!-- 全局操作按钮 -->
<el-button type="primary" link @click="selectAll">[全选]</el-button>
<el-button type="primary" link @click="selectCancel">[取消全选]</el-button>
<!-- 动态循环多个独立表格 -->
<el-table
v-for="(room, roomIndex) in formData.rooms"
:key="roomIndex"
:data="room.prices"
border
:show-header="false"
ref="multipleTable"
@selection-change="(val) => handleSelectChange(val, roomIndex)"
highlight-current-row
>
<!-- 多选框列 -->
<el-table-column type="selection" width="55"></el-table-column>
<!-- 房间号(整表共用) -->
<el-table-column label="房间号" width="150">
<template #default="{row}">
<el-input v-model="room.name" placeholder="房间号" clearable/>
</template>
</el-table-column>
<!-- 租期 -->
<el-table-column label="租期" width="150">
<template #default="{row}">
<el-select v-model="row.term_id" placeholder="租期" clearable filterable>
<el-option label="半年" :value="1" />
<el-option label="一年" :value="2" />
</el-select>
</template>
</el-table-column>
<!-- 付款方式 -->
<el-table-column label="付款方式" width="150">
<template #default="{row}">
<el-select v-model="row.pay_type" placeholder="付款方式" clearable filterable>
<el-option label="月付" :value="1" />
<el-option label="季付" :value="2" />
</el-select>
</template>
</el-table-column>
<!-- 月租金 -->
<el-table-column label="月租金" width="220">
<template #default="{row}">
<el-input v-model="row.price" placeholder="月租金" clearable>
<template #append>元/月</template>
</el-input>
</template>
</el-table-column>
<!-- 默认开关 -->
<el-table-column label="默认" >
<template #default="{row, $index}">
<el-switch
v-model="row.is_default"
active-text="默认"
inline-prompt
:width="50"
:active-value="1"
:inactive-value="0"
/>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, nextTick } from 'vue'
import type { ElTable } from 'element-plus'
// 模拟业务数据源:多个房间 = 多个表格
const formData = reactive({
rooms: [
{ name: 'a', prices: [{ term_id: '', pay_type: '', price: '', is_default: 0 }] },
{ name: 'b', prices: [{ term_id: '', pay_type: '', price: '', is_default: 0 }] }
]
})
// 收集所有表格实例(核心:解决多表格ref覆盖问题)
const multipleTable = ref<(ElTable | null)[]>([])
// 记录【被选中的表格下标】,用于后续批量操作
const selectData = ref<number[]>([])
// 全局全选:所有表格全部勾选
const selectAll = () => {
nextTick(() => {
for (let i = 0; i < formData.rooms.length; i++) {
const table = multipleTable.value[i]
if (table) {
table.toggleAllSelection()
}
// 记录所有表格为选中状态
if (!selectData.value.includes(i)) {
selectData.value.push(i)
}
}
console.log('全选选中索引', selectData.value)
})
}
// 全局取消全选:清空所有表格勾选
const selectCancel = () => {
nextTick(() => {
for (let i = 0; i < formData.rooms.length; i++) {
const table = multipleTable.value[i]
if (table) {
table.clearSelection()
}
}
})
// 清空选中记录
selectData.value = []
console.log('取消全选', selectData.value)
}
// 单表格勾选状态监听:实时维护选中表格索引
const handleSelectChange = (val: any[], roomIndex: number) => {
if (val.length) {
// 表格有选中行,加入选中列表
if (!selectData.value.includes(roomIndex)) {
selectData.value.push(roomIndex)
}
} else {
// 表格无选中行,移出选中列表
selectData.value = selectData.value.filter(item => item !== roomIndex)
}
console.log('当前选中表格索引', selectData.value)
}
</script>
<style ></style>