复现BUG
BUG复现地址:https://www.lilnong.top/static/html/vue-bug-bullet.1.html
BUG修复地址:https://www.lilnong.top/static/html/vue-bug-bullet.2.html
BUG对比地址:https://www.lilnong.top/static/html/vue-bug-bullet.3.html
可以直接查看对比地址,会发现左边的动画异常闪动,而且 DOM 没有被移除
弹幕逻辑
- 一秒 push 一条数据。
- 五条通道循环
- 动画 7s, animationend 事件移除第一个
分析问题
- 第一步,我们先排查逻辑,看看是否因为移除的时候不对,造成了数据错乱。可以看到我们是 shift,基于我们的定长动画,肯定是第一个先执行完成。
animationend(){ this.list.push(this.bulletlist.shift()) },
.bullet-animation{animation: right2left 7s linear both;}
2.经过我们的观察,像是动画突然换行,并且前进了。然后我们打开控制台直接查看 DOM,发现是所有的内容改变,并不是 DOM 节点改变。
3.到了这个我们可以分析出了问题,DOM 被复用了,因为动画是作用在 DOM 上的,当前 DOM 的动画已经完成了。
那么 Vue 的 DOM 复用规则是什么呢?
https://cn.vuejs.org/v2/guide/list.html
当 Vue 正在更新使用
v-for
渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动
DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。 https://cn.vuejs.org/v2/api/#ke
4. 通过上面的文档,我们可以看到,提供一个合理的 key 就可以强制渲染 DOM,可以触发过渡。那么我们就查看一下 key 设置的什么呢?网络异常,图片无法展示|:key="idx"
看来我们找到了问题,因为 idx 和 item 其实没有固定的对应关系的,所以 DOM 被复用了,应该使用 :key="item.id"
总结
让我们遇事不决,量子力学一哈。
- 在 Vue 中使用 v-for 应该搭配一个 :key 来使用。
- :key 需要是一个唯一值,比如 id。最好不要用 index。
- 如果需要强制更新 DOM,我们可以使用 :key 来告诉 Vue 引擎这是两个不同的元素。
相似问题
有的人可能会说,为什么我也用了下标为什么没有报错呢?
其实还有挺多相似问题的,核心点就是有没有进行过修改
- 比如说有排序移动,如果没有提供一个合理的 key,那么就会乱套
- 两个结构相似,但是没有使用 v-for,切换隐藏显示的时候。