如何用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
相关产品推荐
相关产品推荐

