<TransitionGroup>
是一个内置组件,用于对 v-for 列表中的元素或组件的插入、移除和顺序改变添加动画效果。
与 <Transition> 的区别
<TransitionGroup> 支持和 <Transition> 基本相同的 props、CSS 过渡 class 和 JavaScript 钩子监听器,但有以下几点区别:
-
默认情况下,它不会渲染一个容器元素。但你可以通过传入 tag prop 来指定一个元素作为容器元素来渲染。
-
过渡模式在这里不可用,因为我们不再是在互斥的元素之间进行切换。
-
列表中的每个元素都必须有一个独一无二的 key attribute。
-
CSS 过渡 class 会被应用在列表内的元素上,而不是容器元素上。
当在 DOM 内模板中使用时,组件名需要写为 <transition-group>。
进入 / 离开动画
模板
<TransitionGroup name="list" tag="ul"><li v-for="item in items" :key="item">{{ item }}</li>
</TransitionGroup>
样式
.list-enter-active,
.list-leave-active {transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {opacity: 0;transform: translateX(30px);
}
效果
移动动画
上面的示例有一些明显的缺陷:当某一项被插入或移除时,它周围的元素会立即发生“跳跃”而不是平稳地移动。我们可以通过添加一些额外的 CSS 规则来解决这个问题:
.list-move, /* 对移动中的元素应用的过渡 */
.list-enter-active,
.list-leave-active {transition: all 0.5s ease;
}.list-enter-from,
.list-leave-to {opacity: 0;transform: translateX(30px);
}/* 确保将离开的元素从布局流中删除以便能够正确地计算移动的动画。 */
.list-leave-active {position: absolute;
}
现在动画没有那么生硬了,流畅很多
渐进延迟列表动画
通过在 JavaScript 钩子中读取元素的 data attribute,我们可以实现带渐进延迟的列表动画。首先,我们把每一个元素的索引渲染为该元素上的一个 data attribute:
需要添加 gasp 动画库
pnpm install gsap
<script lang="ts" setup>
import { ref, computed } from 'vue'
import gsap from 'gsap'
const list = [{ msg: 'Bruce Lee' },{ msg: 'Jackie Chan' },{ msg: 'Chuck Norris' },{ msg: 'Jet Li' },{ msg: 'Kung Fury' }
]const query = ref('')const computedList = computed(() => {return list.filter((item) => item.msg.toLowerCase().includes(query.value))
})function onBeforeEnter(el) {el.style.opacity = 0el.style.height = 0
}function onEnter(el, done) {gsap.to(el, {opacity: 1,height: '1.6em',delay: el.dataset.index * 0.15,onComplete: done})
}function onLeave(el, done) {gsap.to(el, {opacity: 0,height: 0,delay: el.dataset.index * 0.15,onComplete: done})
}
</script><template><div class="container"><input v-model="query" /><TransitionGrouptag="ul":css="false"@before-enter="onBeforeEnter"@enter="onEnter"@leave="onLeave"><li v-for="(item, index) in computedList" :key="item.msg" :data-index="index">{{ item.msg }}</li></TransitionGroup></div>
</template><style lang="scss" scoped>
.container {
}
</style>