Vue.js 3多自定义Tree组件迭代渲染的疑问及原因解析
我参考Vue.js官方文档的v-for迭代树形组件示例,想在App.vue里迭代渲染多个自定义TreeItem组件。现在有个疑问:为什么TreeItem.vue里传递children列表能正常迭代渲染子TreeItem,但直接在App.vue的TreeItem标签上用v-for却没法渲染多棵树;而用div包裹外层ul并迭代div的写法就能成功实现预期效果?
无法正常渲染的写法
const listOfTrees = ref([{ name: 'My Tree 2', children: [ { name: 'hello' }, { name: 'world' }, { name: 'child folder', children: [ { name: 'child folder', children: [{ name: 'hello' }, { name: 'world' }] }, ] } ] },{ name: 'My Tree', children: [ { name: 'hello' }, { name: 'world' }, { name: 'child folder', children: [ { name: 'child folder', children: [{ name: 'hello' }, { name: 'world' }] }, { name: 'hello' }, { name: 'world' }, { name: 'child folder', children: [{ name: 'hello' }, { name: 'world' }] } ] } ] }])
<template> <ul> <TreeItem class="item" v-for="tree in listOfTrees" :model="treeData"></TreeItem> </ul> </template>
可行的写法
<template> <!-- 用div包裹整个ul并迭代div --> <div v-for="tree in listOfTrees"> <ul> <TreeItem class="item" :model="tree"></TreeItem> </ul> </div> </template>
原因解释
HTML语义约束:
<ul>标签的直接子元素只能是<li>(或<script>、<template>这类特殊标签)。你直接在<ul>下放置多个TreeItem组件时,浏览器会自动修正DOM结构——把不符合规范的TreeItem节点移到<ul>外部,最终导致渲染结果完全偏离预期。而TreeItem组件内部的v-for是在组件自身的<ul>中生成<li>节点,完全符合HTML结构规范,所以子节点能正常渲染。数据绑定错误:第一种写法里你写了
:model="treeData",但循环变量明明是tree,这会导致每个TreeItem拿到的不是当前循环的树数据,而是不存在的treeData,这也是渲染失败的直接原因之一。就算修正了这个绑定,HTML结构不合法导致的浏览器DOM修正,依然会让渲染出问题。第二种写法的合理性:用
<div>包裹每个<ul>,每个<ul>下只放一个TreeItem(组件内部会生成符合规范的<li>结构),整个DOM结构完全符合HTML语义,浏览器不会做额外修正。通过v-for迭代div生成多个独立的树形结构,自然能正常渲染多棵树。
内容的提问来源于stack exchange,提问作者B1GnCheesy

