Vue的Transition组件子元素动画没反应怎么办?

Des.欣龙 阅读 147

在用Vue的v-for循环列表时,给transition组件设置了namemode,但删除元素时只有第一个元素有动画,其他子元素直接消失,这是为啥啊?

代码是这样的:

<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属性都设置了,但开发者工具显示其他元素根本没有过渡样式,只有第一个元素生效了,这到底是哪里出问题了?

我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
书生シ艳鑫
你这问题我太熟悉了,很多刚用 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-groupmove-class,但说实话这更容易出问题。

另外你 CSS 写的 .list-enter-active.list-leave-active 没问题,但记得还要补一个 .list-move,不然移动动画也不会生效,虽然你目前主要卡在删除动画上。

建议改成这样试试:

<template>
<transition-group name="list" tag="ul">
<li v-for="item in items" :key="item.id">{{ item.text }}</li>
</transition-group>
</template>

<script>
export default {
data() {
return {
items: [
{ id: 'a1', text: 'A' },
{ id: 'b2', text: 'B' },
{ id: 'c3', text: 'C' }
]
}
},
methods: {
remove(index) {
this.items.splice(index, 1)
}
}
}
</script>


CSS 也补全点:

.list-enter-active,
.list-leave-active {
transition: all 0.3s ease;
}

.list-enter-from {
opacity: 0;
transform: translateX(20px);
}

.list-leave-to {
opacity: 0;
transform: translateX(-20px);
}

.list-move {
transition: transform 0.3s ease;
}


最后再提醒一句,删数组元素的时候别用 filter 后直接赋值,最好用 splice,虽然理论上 Vue2 都能检测到,但有时候 filter 会触发多次更新,动画容易乱套。
点赞 1
2026-02-26 09:18
萌新.怡然
你这问题我之前也踩过坑,根本原因是用了 transition-group 但子元素没包一层独立的 transition。transition-group 只是给整个列表容器加过渡状态,真正要让每个 item 有完整的进入和离开动画,得靠里面的元素自己触发。

你的代码现在只写了 .list-enter-active 和 .list-leave-active,但漏了 enter-from/leave-to 这些初始状态,而且最关键的是:li 元素本身没有设置 key 和独立的包裹结构来支撑逐个动画。

我的做法是把每个 li 包一层 transition,或者更简单点 —— 直接在 transition-group 里确保每个子项都有正确的类名过渡体系。比如这样改:

<transition-group name="list" tag="ul">
<li
v-for="item in items"
:key="item.id"
class="list-item"
>
{{ item.text }}
</li>
</transition-group>


然后 CSS 要补全所有阶段:

.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from {
opacity: 0;
transform: translateY(-30px);
}
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
/* 注意:这里 leave-to 结束后元素才被移除 */


还有一点容易忽略:必须给每个 li 加唯一的 :key,你虽然加了,但确认下 item.id 真的是唯一且稳定不变的?如果 id 是索引或者会变的,Vue 就没法追踪元素,动画也会错乱。

最后检查浏览器开发者工具里的元素样式,在删除时看看其他 li 有没有加上 list-leave-active 这种类名,如果没有,说明 transition-group 没正确触发每个节点的生命周期,大概率就是 key 不对或者结构问题。

试试看,一般补上 enter-from 和 leave-to 就好了。
点赞 8
2026-02-12 18:01