总结:
-
Vue3 中单文件组件最好也用单个根节点包裹, 避免被其他组件遍历时, 因为组件内部存在多个根节点(以及根节点的 v-if)导致问题
-
<template v-for
遍历时不要将 key 放到内部元素上, 就放在 template 上
场景 1: template v-for 错误
背景:
Vue3 项目 - 时间轴组件 - 遍历渲染单个时间轴条目组件 - 条目组件遍历渲染显示字段, 编辑某个条目后, 会重新请求数据列表替换原数据数组重新渲染, 偶现此报错
排查:
条目组件内容较简单, 注释怀疑的代码块, 排查问题, 发现是如下代码导致问题:
<template v-for="field in showFields">
<div
v-if="isFieldShouldShow(field)"
:key="field.id"
>
<!-- 显示字段组件 -->
</div>
</template>
解决:
将 :key 放到 template 上解决
(之前这么写是因为 vue2 项目里, :key 到 template 上, 编辑器会标红, 但现在修改后也不会标红了)
场景 2: 子组件内部首个根节点根据 v-if 显示
背景:
Vue3 项目 - 时间轴组件 - 遍历渲染单个时间轴条目组件 - 顶部存在多个 tab , 首个 tab 为全部条目, 其他 tab 按条件显示部分条目, 偶现此报错
或
Vue3 项目 - 时间轴组件 - 遍历渲染单个时间轴条目组件 - 已加载当前 tab 下大量数据, 再手动新建一条数据, 新建完后刷新当前 tab 数据, 偶现此报错
排查:
<!-- line 父组件遍历加载 item 子组件 -->
<LineItem
v-for="item in itemList"
:key="item.id"
:itemData="item"
// ...
>
</LineItem>
<!-- 子组件没有根节点, 首个节点有 v-if 判断 -->
<template>
<!-- 日期 -->
<div
v-if="itemData.dateStr"
class="line-splitDate"
>{{ itemData.dateStr }}</div>
<!-- 条目本体 -->
<div
v-bind="$attrs"
class="LineItem"
></div>
</template>
解决:
- 子组件外面再包裹一层 div 即可
- 因为都是在已存在数据时再次刷新数据时出问题, 推测可以通过在刷新数据前清空旧数据再重新渲染新数据解决