TransitionGroup
<TransitionGroup> 是一个内置组件,用于对 v-for 列表中的元素或组件的插入、移除和顺序改变添加动画效果。
1.组件属性
<TransitionGroup> 拥有与 <Transition> 除了 mode 以外所有的 props,并增加了两个额外的 props:
<TransitionGroup> 抛出与 <Transition> 相同的事件。
ts
interface TransitionGroupProps extends Omit<TransitionProps, 'mode'> {
/**
* 如果未定义,则渲染为片段 (fragment)。
*/
tag?: string
/**
* 用于自定义过渡期间被应用的 CSS class。
* 在模板中使用 kebab-case,例如 move-class="xxx"
*/
moveClass?: string
}2.和Transition的区别
<TransitionGroup> 支持和 <Transition> 基本相同的 props、CSS 过渡 class 和 JavaScript 钩子监听器,但有以下几点区别:
- 默认情况下,它不会渲染一个容器元素。但你可以通过传入
tagprop 来指定一个元素作为容器元素来渲染。 - 过渡模式在这里不可用,因为我们不再是在互斥的元素之间进行切换。
- 列表中的每个元素都必须有一个独一无二的
keyattribute。 - CSS 过渡 class 会被应用在列表内的元素上,而不是容器元素上。
WARNING
注意,每个 <transition-group> 的子节点必须有独立的 key,动画才能正常工作
当在 DOM 内模板中使用时,组件名需要写为 <transition-group>。
3.进入/离开动画
这里是 <TransitionGroup> 对一个 v-for 列表添加进入 / 离开动画的示例:
vue
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item">
{{ item }}
</li>
</TransitionGroup>css
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}4.移动动画
上面的示例有一些明显的缺陷:当某一项被插入或移除时,它周围的元素会立即发生“跳跃”而不是平稳地移动。我们可以通过添加一些额外的 CSS 规则来解决这个问题:
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;
}现在看起来有那么一丝丝的顺滑,甚至对整个列表执行洗牌的动画也都非常流畅:
5.渐进延迟列表动画
通过在 JavaScript 钩子中读取元素的 data attribute,我们可以实现带渐进延迟的列表动画。首先,我们把每一个元素的索引渲染为该元素上的一个 data attribute:
vue
<input type="text" v-model="query" class="ipt" />
<TransitionGroup
tag="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>接着,在 JavaScript 钩子中,我们基于当前元素的 data attribute 对该元素的进场动画添加一个延迟。以下是一个基于 GSAP library 的动画示例:
js
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 onEnter(el, done) {
gsap.to(el, {
opacity: 1,
height: '1.6em',
delay: el.dataset.index * 0.15,
onComplete: done,
})
}
function onBeforeEnter(el) {
el.style.opacity = 0
el.style.height = 0
}
function onLeave(el, done) {
gsap.to(el, {
opacity: 0,
height: 0,
delay: el.dataset.index * 0.15,
onComplete: done,
})
}- Bruce Lee
- Jackie Chan
- Chuck Norris
- Jet Li
- Kung Fury
