Vue3 的过渡动画组件 Transition 和 TransitionGroup
Vue3 提供了 Transition
和 TransitionGroup
两个过渡动画组件,其中 Transition
主要用于元素或组件使用 v-if
、v-show
和路由切换时显示过渡动画,TransitionGroup
用于 v-for
渲染的列表项添加或移除时显示过渡动画。
Transition
Transition
可以实现在组件或元素插入到页面和从页面移除时显示过渡动画,这个组件在 Vue2 也出现过。
通过 v-if
、v-show
、组件路由跳转都可以使用 Transition
的过渡动画。
组件使用
下面是一个简单的 Transition
:
<template>
<div>
<button type="button" @click="show = !show">开关</button>
<Transition>
<div id="box" v-show="show"></div>
</Transition>
</div>
</template>
<script setup>
import { ref } from 'vue';
const show = ref(true);
</script>
<style>
/*Transition 的过渡时间和动画*/
.v-enter-active,.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,.v-leave-to {
opacity: 0;
}
</style>
上面的 HTML 代码中包含一个 div
和一个 button
,点击按钮 div
就可以实现淡入淡出的显示和隐藏,过渡动画的时间是 0.5秒。
Transition
的动画和时间都需要通过 CSS 来定义,如果没有 CSS 的话,是不会有过渡动画效果的。
过渡动画的时间和动画也需要放到指定的 class
,下面是 class
说明:
.v-enter-from
: 进入动画的起始状态。在元素插入之前添加,在元素插入完成后的下一帧移除。.v-enter-active
: 进入动画的生效状态。应用于整个进入动画阶段。在元素被插入之前添加,在过渡或动画完成之后移除。这个 class 可以被用来定义进入动画的持续时间、延迟与速度曲线类型。.v-enter-to
: 进入动画的结束状态。在元素插入完成后的下一帧被添加 (也就是.v-enter-from
被移除的同时),在过渡或动画完成之后移除。.v-leave-from
: 离开动画的起始状态。在离开过渡效果被触发时立即添加,在一帧后被移除。.v-leave-active
: 离开动画的生效状态。应用于整个离开动画阶段。在离开过渡效果被触发时立即添加,在过渡或动画完成之后移除。这个 class 可以被用来定义离开动画的持续时间、延迟与速度曲线类型。.v-leave-to
: 离开动画的结束状态。在一个离开动画被触发后的下一帧被添加 (也就是.v-leave-from
被移除的同时),在过渡或动画完成之后移除。
上面实现的淡入淡出主要就是更改透明度,在 .v-enter-from
元素插入之前把透明度设置为 0,在 .v-enter-active
元素插入之后恢复默认的透明度,同时设置过渡时间为 0.5秒,隐藏的时候也是一样的。
给过渡效果命名
有时候可能会遇到一个组件中,不同的元素需要使用不同的过渡效果,如果还按照上面的方法直接给元素套 Transition
和 class
的话,可能会导致所有元素使用的都是相同的过渡效果。
给过渡效果命名可以在 Transition
组件上传入一个 name
prop ,如下:
<Transition name="box">
<div id="box" v-show="show"></div>
</Transition>
给 Transition
加入过渡名称后 class
的前缀也不能再使用 v-
开头,需要使用 名称-
作为前缀。
上面给 Transition
传入了一个 box
作为过渡名称,它的 class
就是:
.box-enter-active,.box-leave-active {
transition: opacity 0.5s ease;
}
.box-enter-from,.box-leave-to {
opacity: 0;
}
使用 CSS 的 animation 动画
Transition
组件也可以使用 CSS 的 animation
动画。在 CSS animation
动画中,一般只需要在 .v-enter-active
和 .v-leave-active
两个 class 下声明。
下面是一个简单的 Transition
CSS animation
动画:
<Transition>
<div id="box" v-show="show"></div>
</Transition>
/*进入的动画*/
.v-enter-active {
animation: box-enter 0.5s cubic-bezier(0.0, 0.0, 1.0, 1.0);
}
@keyframes box-enter {
0% {
width: 0;
height: 0;
}
100% {
width: 150px;
height: 150px;
}
}
/*离开的动画*/
.v-leave-active {
animation: box-leave 0.5s cubic-bezier(0.0, 0.0, 1.0, 1.0);
}
@keyframes box-leave {
0% {
width: 150px;
height: 150px;
}
100% {
width: 0;
height: 0;
}
}
上面实现的是一个简单的缩放动画,显示的时候慢慢放大,隐藏的时候慢慢缩小。
在 animation
后面的 box-enter
和 box-leave
是定义动画名称,主要用于 @keyframes
设置动画。0.5s
是动画时间。cubic-bezier(0.0, 0.0, 1.0, 1.0)
是一个控制动画匀速运动的函数。下面的 @keyframes
就是设置动画在不同阶段的状态,我上面只是设置了 0%
和 100%
的状态。
动画效果如下
自定义过渡 class
除了使用官方定义的 class 外,你也可以自定义过渡的 class,自定义 class 可以通过给 Transition
组件传入指定的 prop 来定义。
下面是可以传入的 prop:
enter-from-class
enter-active-class
enter-to-class
leave-from-class
leave-active-class
leave-to-class
这些 prop 名称的作用可以参考上面的组件使用的 class 说明。
还是上面的 CSS animation
动画,自定义 class 如下:
<Transition enter-active-class="show" leave-active-class="hide">
<div id="box" v-show="show"></div>
</Transition>
/*进入的动画*/
.show {
animation: box-enter 0.5s cubic-bezier(0.0, 0.0, 1.0, 1.0);
}
/*离开的动画*/
.hide {
animation: box-leave 0.5s cubic-bezier(0.0, 0.0, 1.0, 1.0);
}
Transition 的 JavaScript 钩子
Transition
提供了一些钩子事件,通过监听钩子事件,你可以使用 JavaScript 来实现过渡动画,也可以根据过渡阶段来加载数据。
下面是事件说明:
before-enter
: 在元素被插入到页面前调用,相当于enter-from
enter
: 在元素插入到页面的下一帧调用,可以用来设置动画after-enter
: 过渡完成时调用enter-cancelled
: 也是在过渡完成后调用,在after-enter
之后before-leave
: 在离开过渡开始前调用leave
: 在离开过渡开始时调用,可以用来设置过渡动画after-leave
: 在离开过渡完成且元素被移除时调用leave-cancelled
: 在过渡完成后调用,只能在v-show
使用
下面实现元素淡入后显示文字,元素淡出前移除文字:
<Transition @after-enter="onAfterEnter" @before-leave="onBeforeLeave">
<div id="box" v-show="show">{{ text }}</div>
</Transition>
JavaScript setup:
import { ref } from 'vue';
const text = ref('');
// 进入过渡完成时调用
function onAfterEnter() {
text.value = 'Hello';
}
// 离开过渡开始前调用
function onBeforeLeave() {
text.value = '';
}
这里的过渡动画使用的还是 CSS 动画,下面是实现效果:
如果你的动画是通过 JS 实现,不需要使用 CSS 的话,可以给 Transition
组件加一个 :css="false"
属性来跳过 CSS 过渡检测,可以提升性能和防止 CSS 干扰过渡效果。
封装过渡效果
如果你需要在多个组件中使用同一个过渡效果的话,也可以使用插槽 slot
来封装过渡效果。
下面还是封装一个实现淡入淡出的插槽组件,组件命名为 FadeInAndFadeOut.vue
:
<template>
<Transition name="fade">
<slot></slot>
</Transition>
</template>
<style>
.fade-enter-active,.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,.fade-leave-to {
opacity: 0;
}
</style>
在其他组件中调用上面封装的淡入淡出过渡:
<template>
<div>
<FadeInAndFadeOut>
<div id="box" v-show="show"></div>
</FadeInAndFadeOut>
</div>
</template>
<script setup>
import FadeInAndFadeOut from './FadeInAndFadeOut.vue';
</script>
初次渲染时使用过渡效果
Transition 在打开页面第一次渲染的时候是不会有过渡效果的,如果需要在第一次渲染的时候就显示过渡效果可以给 Transition 组件加一个 appear
属性,如下:
<Transition appear></Transition>
TransitionGroup
TransitionGroup
主要用于 v-for
渲染的列表项元素添加或移除时显示过渡动画。
TransitionGroup
也可以使用和 Transition
一样的 CSS class,也可以使用 name
prop 更改 CSS class 前缀,也可以使用和 Transition
一样的事件钩子。
进入和离开动画
下面是一个简单的 TransitionGroup
列表过渡:
<TransitionGroup name="list" tag="ul">
<li v-for="item in list" :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);
}
列表过渡效果如下:
我上面的 TransitionGroup
组件内直接就写 li
元素了,没有写列表的外层 ul
,我给 TransitionGroup
组件加了一个 tag=“ul”
,通过 tag
属性也能在 li
的外层渲染一个 ul
。
在 TransitionGroup
内使用 v-for
渲染的列表每个列表项都需要有一个单独的 :key
值,:key
值不能出现重复,也不能使用 v-for="(item, index) of list"
这种自动生成的索引值。
平滑移动列表项
上面的过渡动画在列表中间插入或移除元素时,周围的列表项会立即移动,没有过渡动画。
下面修改一下 CSS,当列表发生变化时,让周围的列表项也能平滑的移动:
.list-enter-active,.list-leave-active,.list-move {
transition: all 0.5s ease;
}
.list-enter-from,.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
.list-leave-active {
position: absolute;
}
效果如下:
版权声明:本文为原创文章,版权归 Mr. Ma's Blog 所有,转载请联系博主获得授权。
本文地址:https://www.misterma.com/archives/925/
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。