Vue的Transition组件子元素动画没反应怎么办?
在用Vue的v-for循环列表时,给transition组件设置了name和mode,但删除元素时只有第一个元素有动画,其他子元素直接消失,这是为啥啊?
代码是这样的:
<transition-group name="list" tag="ul">
<li v-for="item in items" :key="item.id">{{ item.text }}</li>
</transition-group>
CSS写了.list-enter-active和.list-leave-active,连transition属性都设置了,但开发者工具显示其他元素根本没有过渡样式,只有第一个元素生效了,这到底是哪里出问题了?
transition-group的人都会踩这个坑。问题出在
key上。你写的:key="item.id"看起来没问题,但关键是你用的item.id是不是真的唯一?或者更常见的情况是:你删的是数组里的某个元素,但id并没跟着变动,导致 Vue 把删掉的元素和后面的元素搞混了,以为它们是同一个 DOM 节点。举个例子,假设你有三个元素
[{id: 1}, {id: 2}, {id: 3}],你删掉第二个,变成[{id: 1}, {id: 3}],但如果你的id是从 0 开始的索引,那删完之后第二个元素的id就变成了2,而 Vue 会误以为它和原来的第三个元素是同一个,于是跳过动画直接干掉了。解决方案有两个思路:
第一个,也是最推荐的,确保
key是绝对唯一的,比如用 UUID 或者后端返回的唯一 ID,别用数组索引当 key。第二个,如果你确实想用索引,那得配合
transition-group的move-class,但说实话这更容易出问题。另外你 CSS 写的
.list-enter-active和.list-leave-active没问题,但记得还要补一个.list-move,不然移动动画也不会生效,虽然你目前主要卡在删除动画上。建议改成这样试试:
CSS 也补全点:
最后再提醒一句,删数组元素的时候别用
filter后直接赋值,最好用splice,虽然理论上 Vue2 都能检测到,但有时候 filter 会触发多次更新,动画容易乱套。你的代码现在只写了 .list-enter-active 和 .list-leave-active,但漏了 enter-from/leave-to 这些初始状态,而且最关键的是:li 元素本身没有设置 key 和独立的包裹结构来支撑逐个动画。
我的做法是把每个 li 包一层 transition,或者更简单点 —— 直接在 transition-group 里确保每个子项都有正确的类名过渡体系。比如这样改:
然后 CSS 要补全所有阶段:
还有一点容易忽略:必须给每个 li 加唯一的 :key,你虽然加了,但确认下 item.id 真的是唯一且稳定不变的?如果 id 是索引或者会变的,Vue 就没法追踪元素,动画也会错乱。
最后检查浏览器开发者工具里的元素样式,在删除时看看其他 li 有没有加上 list-leave-active 这种类名,如果没有,说明 transition-group 没正确触发每个节点的生命周期,大概率就是 key 不对或者结构问题。
试试看,一般补上 enter-from 和 leave-to 就好了。