Vue父表格点击行时子表格重复显示问题排查与解决请求
问题分析与解决方案
嘿,我发现你遇到的子表格重复显示问题根源啦!你在HTML模板里做了重复的嵌套循环,导致同一组地区数据被多次渲染。
具体问题点
看你这段代码:
<template v-for="(xy, indexStop) in DistrictGDP" v-if="opened.includes(row.Id) && row.Id==xy.Id"> <!-- 子表格表头 --> <template v-for="xy in DistrictGDP" v-if="opened.includes(row.Id) && row.Id==xy.Id"> <!-- 地区数据行 --> </template> </template>
这里外层已经通过v-for遍历了所有和当前邦匹配的地区,然后内层又再次遍历整个DistrictGDP数组并筛选相同条件的地区。举个例子:Rajasthan有2个地区,外层循环会执行2次,每次内层又会循环2次,最终就会渲染出4行重复的地区数据(2×2),这就是重复的核心原因。而且表头也会跟着外层循环重复出现,这也是额外的问题。
修复方案
我们需要简化结构,去掉重复的循环,同时确保表头只渲染一次。下面是修改后的完整代码:
修改后的HTML部分
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="app"> <div class="table"> <table class="table-fill"> <thead> <tr> <th class="text-center">State/UT</th> <th class="text-center">1999-00</th> <th class="text-center">2000-01</th> </tr> </thead> <template v-for="row in stateGDP"> <tr @click="toggle(row.Id)" :class="{ opened: opened.includes(row.Id) }"> <td>{{ row.State }}</td> <td>{{ row['1999-00'] }}</td> <td>{{ row['2000-01'] }}</td> </tr> <!-- 仅当当前邦展开时显示子表格 --> <template v-if="opened.includes(row.Id)"> <!-- 子表格表头:只渲染一次 --> <thead> <tr> <th class="text-center">District</th> <th class="text-center">1999-00</th> <th class="text-center">2000-01</th> </tr> </thead> <!-- 筛选并遍历当前邦对应的地区数据 --> <tr v-for="district in DistrictGDP.filter(d => d.Id === row.Id)" :key="district.District"> <td>{{district.District}}</td> <td>{{district['1999-00']}}</td> <td>{{district['2000-01']}}</td> </tr> </template> </template> </table> </div> </div>
关键修改说明
- 移除重复循环:去掉了外层多余的
v-for="(xy, indexStop) in DistrictGDP",直接用v-if="opened.includes(row.Id)"判断是否展开子表格。 - 表头只渲染一次:把子表格表头放在展开判断的模板里,确保每个邦展开时只显示一个表头。
- 单次筛选数据:用
DistrictGDP.filter(d => d.Id === row.Id)一次性筛选出当前邦的所有地区,再遍历这些结果,每个地区只会渲染一次。 - 添加key属性:给子表格的行加上
:key="district.District",符合Vue列表渲染的最佳实践,避免控制台警告。
进阶优化(可选)
如果你的数据量比较大,每次渲染都用filter会有点性能开销,你可以在Vue的computed属性里预先把地区数据按邦的Id分组:
修改后的Vue代码
var app = new Vue({ el: "#app", data(){ return { opened:[], stateGDP: [ { State: "Rajasthan", "1999-00": "2547", "2000-01": "3679",Id:"23" }, { State: "Orissa", "1999-00": "38714", "2000-01": "38814",Id:"24" } ], DistrictGDP: [ { State: "Rajasthan", District: "Jaipur", "1999-00": "2547", "2000-01": "3679", Id:"23" }, { State: "Rajasthan", District: "Jodhpur", "1999-00": "2557", "2000-01": "3639", Id:"23" }, { State: "Orissa", District: "Bhubaneswar", "1999-00": "1983", "2000-01": "2068", Id:"24" }, { State: "Orissa", District: "Puri", "1999-00": "1923", "2000-01": "2008", Id:"24" } ] } }, computed: { groupedDistricts() { // 按Id分组地区数据 return this.DistrictGDP.reduce((acc, district) => { if (!acc[district.Id]) { acc[district.Id] = []; } acc[district.Id].push(district); return acc; }, {}); } }, methods:{ toggle:function(Id) { const index = this.opened.indexOf(Id); if (index > -1) { this.opened.splice(index, 1) } else { this.opened.push(Id) } } } })
然后HTML里的遍历部分改成:
<tr v-for="district in groupedDistricts[row.Id]" :key="district.District">
这样分组只会在数据变化时重新计算,渲染时直接取分组好的数据,性能会更好。
内容的提问来源于stack exchange,提问作者Lakshay Khandelwal
相关产品推荐
相关产品推荐

