You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Vue v-for循环从嵌套对象生成含合并行的表格?

用Vue v-for生成带rowspan的嵌套表格解决方案

看起来你是要把嵌套的学校-班级-学生数据渲染成带有rowspan合并单元格的表格对吧?之前嵌套v-for没搞对大概率是因为没处理好rowspan的计算和单元格的显示逻辑——毕竟这种合并单元格的表格,只有每组的第一行需要显示跨多行的表头单元格,后面的行要跳过这些列。

首先先提一下:你给出的原始JSON数据里有语法错误,每个对象之间缺了逗号,我先帮你修正了(比如学生数组里的对象之间、班级数组的对象之间),修正后的数据是这样的:

const schools = [
  { 
    "school_name": "Test School A", 
    "classes": [
      { 
        "class_name": "Class A", 
        "students": [ 
          { "student_name": "John", "grade" : "A"},
          { "student_name": "Andrew", "grade" : "B"},
          { "student_name": "Peter", "grade" : "C"} 
        ] 
      },
      { 
        "class_name": "Class B", 
        "students": [ 
          { "student_name": "Alice", "grade" : "C"},
          { "student_name": "Ronald", "grade" : "A"},
          { "student_name": "Katherine", "grade" : "B"} 
        ] 
      }
    ]
  },
  { 
    "school_name": "Test School B", 
    "classes": [
      { 
        "class_name": "Class C", 
        "students": [ 
          { "student_name": "John", "grade" : "B"},
          { "student_name": "Ronald", "grade" : "B"},
          { "student_name": "Jacob", "grade" : "B"} 
        ] 
      },
      { 
        "class_name": "Class D", 
        "students": [ 
          { "student_name": "Maia", "grade" : "C"},
          { "student_name": "Narine", "grade" : "C"},
          { "student_name": "Olivia", "grade" : "A"} 
        ] 
      }
    ]
  }
];

接下来是核心的Vue模板实现思路:

  • 先遍历学校数组,对每个学校,计算它的总学生数(所有班级的学生数之和),作为学校单元格的rowspan值。
  • 然后遍历该学校的班级数组,对每个班级,计算它的学生数,作为班级单元格的rowspan值。
  • 最后遍历班级的学生数组,只有第一个学生所在的行需要显示学校和班级的单元格,后面的学生行要跳过这两列,只显示学生信息。

下面是完整的Vue组件代码:

<template>
  <table border="1">
    <tbody>
      <!-- 遍历学校 -->
      <template v-for="(school, schoolIndex) in schools" :key="schoolIndex">
        <!-- 遍历学校下的班级 -->
        <template v-for="(cls, classIndex) in school.classes" :key="classIndex">
          <!-- 遍历班级下的学生 -->
          <tr v-for="(student, studentIndex) in cls.students" :key="studentIndex">
            <!-- 只有第一个班级的第一个学生显示学校单元格 -->
            <td v-if="classIndex === 0 && studentIndex === 0" :rowspan="getTotalStudents(school)">
              {{ school.school_name }}
            </td>
            <!-- 只有每个班级的第一个学生显示班级单元格 -->
            <td v-if="studentIndex === 0" :rowspan="cls.students.length">
              {{ cls.class_name }}
            </td>
            <!-- 学生信息单元格 -->
            <td>{{ student.student_name }}</td>
            <td>{{ student.grade }}</td>
          </tr>
        </template>
      </template>
    </tbody>
  </table>
</template>

<script>
export default {
  data() {
    return {
      schools: [
        { 
          "school_name": "Test School A", 
          "classes": [
            { 
              "class_name": "Class A", 
              "students": [ 
                { "student_name": "John", "grade" : "A"},
                { "student_name": "Andrew", "grade" : "B"},
                { "student_name": "Peter", "grade" : "C"} 
              ] 
            },
            { 
              "class_name": "Class B", 
              "students": [ 
                { "student_name": "Alice", "grade" : "C"},
                { "student_name": "Ronald", "grade" : "A"},
                { "student_name": "Katherine", "grade" : "B"} 
              ] 
            }
          ]
        },
        { 
          "school_name": "Test School B", 
          "classes": [
            { 
              "class_name": "Class C", 
              "students": [ 
                { "student_name": "John", "grade" : "B"},
                { "student_name": "Ronald", "grade" : "B"},
                { "student_name": "Jacob", "grade" : "B"} 
              ] 
            },
            { 
              "class_name": "Class D", 
              "students": [ 
                { "student_name": "Maia", "grade" : "C"},
                { "student_name": "Narine", "grade" : "C"},
                { "student_name": "Olivia", "grade" : "A"} 
              ] 
            }
          ]
        }
      ]
    };
  },
  methods: {
    // 计算学校的总学生数
    getTotalStudents(school) {
      return school.classes.reduce((total, cls) => total + cls.students.length, 0);
    }
  }
};
</script>

<style scoped>
table {
  border-collapse: collapse;
}
td {
  padding: 8px;
  text-align: left;
}
</style>

关键逻辑解释:

  • 学校单元格的显示:只有当当前是学校的第一个班级,且该班级的第一个学生时,才渲染学校单元格,并且设置rowspan为该学校的总学生数(通过getTotalStudents方法计算)。
  • 班级单元格的显示:只有当当前是班级的第一个学生时,才渲染班级单元格,rowspan设为该班级的学生数。
  • 嵌套的<template>标签:用<template>来包裹v-for循环,这样不会生成额外的DOM元素,只渲染需要的<tr>标签。

这样渲染出来的表格就完全符合你给出的示例结构,每个学校和班级的单元格都会跨对应的行数,表格结构正确。

内容的提问来源于stack exchange,提问作者Jun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:08:16