主子表联动实现文档
概述
主子表联动是一种常见的数据展示模式,点击主表(上表)的某一行时,下方的子表会自动加载并显示与该行相关的详细数据。
实现原理
1. 数据结构设计
主表数据结构(线路信息):
MainTableData: [
{
id: '1',
routeName: '北京-上海',
origin: '北京',
destination: '上海',
goodsName: '钢材',
createdTime: '2025-11-18',
// ...其他字段
}
]
子表数据结构(价格信息):
SubTableData: [
{
id: '1',
routeId: '1', // 关联主表的ID
price: 100,
priceChange: '1',
unit: '1',
recordDate: '2025-11-18',
// ...其他字段
}
]
2. 核心实现步骤
步骤1:定义状态变量
data() {
return {
MainTableData: [], // 主表数据
SubTableData: [], // 子表数据
currentRow: null, // 当前选中的主表行
}
}
步骤2:主表添加行点击事件
<el-table
:data="MainTableData"
@row-click="rowClick"
highlight-current-row
>
<!-- 表格列定义 -->
</el-table>
关键属性说明:
@row-click="rowClick"- 绑定行点击事件highlight-current-row- 高亮当前选中行
步骤3:实现行点击处理方法
methods: {
// 主表行点击事件
rowClick(row) {
// 1. 保存当前选中行
this.currentRow = row
// 2. 根据主表ID加载子表数据
this.fetchSubData(row.id)
},
// 获取子表数据
fetchSubData(routeId) {
if (!routeId) {
this.SubTableData = []
return
}
const params = {
routeId: routeId, // 使用主表ID作为查询条件
}
getPricesList(params)
.then(response => {
if (response && response.code === '1000') {
this.SubTableData = response.data || []
}
})
.catch(error => {
console.error('获取价格列表失败', error)
this.$message.error('获取价格列表失败')
})
}
}
步骤4:子表展示
<el-row class="bg-white mt10">
<!-- 显示当前选中的主表信息 -->
<el-row>
<el-col :span="24">
<div class="cargo-header">
<div class="cargo-source-no">
线路名称 | {{ currentRow ? currentRow.routeName : '' }}
</div>
</div>
</el-col>
</el-row>
<!-- 子表操作按钮 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button @click="handleSubAdd">新增</el-button>
</el-col>
</el-row>
<!-- 子表数据展示 -->
<el-row>
<el-table :data="SubTableData" border>
<!-- 子表列定义 -->
</el-table>
</el-row>
</el-row>
完整流程图
用户点击主表某一行
↓
触发 @row-click 事件
↓
调用 rowClick(row) 方法
↓
保存当前选中行到 currentRow
↓
调用 fetchSubData(row.id)
↓
发送API请求获取子表数据
↓
SubTableData 更新
↓
子表自动重新渲染显示新数据
关键技术点
1. 数据关联
- 主表的
id字段与子表的routeId字段建立关联关系 - 通过主表ID作为查询参数获取对应的子表数据
2. 状态管理
// 保存当前选中行
this.currentRow = row
// 清空之前的子表数据
this.SubTableData = []
// 加载新的子表数据
this.fetchSubData(row.id)
3. 初始化处理
fetchData() {
getRoutesList(params)
.then(response => {
// 重置选中状态
this.currentRow = null
this.SubTableData = []
this.MainTableData = response.data.list || []
})
}
当主表数据刷新时,清空选中状态和子表数据,避免显示脏数据。
4. 子表操作关联主表
// 子表新增时,自动关联当前选中的主表
handleSubAdd() {
if (!this.currentRow) {
this.$message.warning('请先选择一条线路记录')
return
}
this.SubForm = {
id: '',
routeId: this.currentRow.id, // 关联主表ID
// ...其他字段
}
this.subDialogVisible = true
}
// 子表数据保存后,刷新当前主表行的子表数据
submitSubForm() {
addPrice(formData)
.then(response => {
this.$message.success('新增成功')
this.subDialogVisible = false
// 刷新当前选中行的子表数据
this.fetchSubData(this.currentRow.id)
})
}
优化建议
1. 防止重复请求
rowClick(row) {
// 如果点击的是同一行,不重复请求
if (this.currentRow && this.currentRow.id === row.id) {
return
}
this.currentRow = row
this.fetchSubData(row.id)
}
2. 添加加载状态
data() {
return {
subTableLoading: false, // 子表加载状态
}
}
fetchSubData(routeId) {
this.subTableLoading = true
getPricesList(params)
.then(response => {
this.SubTableData = response.data || []
})
.finally(() => {
this.subTableLoading = false
})
}
<el-table :data="SubTableData" v-loading="subTableLoading">
3. 空状态提示
<el-empty
v-if="!currentRow"
description="请在上方选择一条线路记录"
/>
<el-table
v-else
:data="SubTableData"
>
总结
主子表联动的核心是:
- 事件监听:通过
@row-click监听主表行点击 - 状态管理:保存当前选中行到
currentRow - 数据关联:使用主表ID查询对应的子表数据
- 响应式更新:子表数据更新后自动重新渲染
这种模式适用于任何具有主从关系的数据展示场景,如:订单-订单明细、部门-员工、分类-商品等。