文章目录
- 1. transition组件
- 1.1. 基本用法
- 1.2. css过渡class介绍
- 1.3. 过渡效果命名
- 1.3.1. 基本用法
- 1.4. 配合自定义动画(animation)使用
- 1.5. 自定义过渡 class
- 1.6. `<Transition>`组件生命周期
- 1.7. transition 常用场景
- 2. transition-group组件
- 2.1. 基本用法
在Vue3中,内置了许多组件,可以帮助我们更方便地开发应用程序。在本篇博客中,我们将介绍
transition
&
transition-group
组件,以及它们的用法。
1. transition组件
<transition>
组件用于在元素插入或删除时添加过渡效果。例如,当我们在一个列表中添加或删除项目时,可以使用<transition>
组件为这些操作添加一个动画效果。具体用法如下:
1.1. 基本用法
<template>
<div>
<button @click="show = !show">显示/隐藏</button>
<transition>
<div v-if="show">Hello, World!</div>
</transition>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const show = ref(false)
</script>
<style scoped>
.v-enter-active,
.v-leave-active {
transition: opacity 2s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
</style>
在上面的代码中,我们使用<transition>
组件将<div>
元素包裹起来。当条件show
为true
时,<div>
元素会被插入到DOM中,并且会显示一个过渡动画。当条件show
为false
时,<div>
元素会从DOM中删除。
1.2. css过渡class介绍
未命名时一共有 6 个应用于进入与离开过渡效果的 CSS 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 被移除的同时),在过渡或动画完成之后移除。
1.3. 过渡效果命名
对于一个有名字的过渡效果,对它起作用的过渡 class
会以其名字而不是v
作为前缀。下面是一个过渡命名的例子:
1.3.1. 基本用法
<template>
<div>
<button @click="show = !show">显示/隐藏</button>
<transition name="hide">
<div v-if="show">Hello, World!</div>
</transition>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const show = ref(false)
</script>
<style scoped>
.hide-enter-active,
.hide-leave-active {
transition: opacity 2s ease;
}
.hide-enter-from,
.hide-leave-to {
opacity: 0;
}
</style>
注意:<Transition>
一般都会搭配原生 CSS 过渡
一起使用,正如上面的例子中所看到的那样。这个transition CSS
属性是一个简写形式,使我们可以一次定义一个过渡的各个方面,包括需要执行动画的属性
、持续时间
和速度曲线
。
1.4. 配合自定义动画(animation)使用
原生 CSS 动画
和CSS transition
的应用方式基本上是相同的,只有一点不同,那就是*-enter-from
不是在元素插入后立即移除,而是在一个animationend
事件触发时被移除。
对于大多数的 CSS 动画
,我们可以简单地在 *-enter-active
和*-leave-active class
下声明它们。下面是一个示例:
<template>
<div>
<button @click="show = !show">显示/隐藏</button>
<transition name="hide">
<div v-if="show">Hello, World!</div>
</transition>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const show = ref(false)
</script>
<style scoped>
.hide-enter-active {
animation: scsle-in 0.5s;
}
.hide-leave-active {
animation: scsle-in 0.5s reverse;
}
@keyframes scsle-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1);
}
}
</style>
1.5. 自定义过渡 class
可以向<Transition>
传递以下的 props 来指定自定义的过渡 class:
- enter-from-class
- enter-active-class
- enter-to-class
- leave-from-class
- leave-active-class
- leave-to-class
传入的这些 class 会覆盖相应阶段的默认 class 名。这个功能在你想要在 Vue 的动画机制下集成其他的第三方 CSS 动画库时非常有用,比如 Animate.css
:
<template>
<button @click="show = !show">Toggle</button>
<Transition
name="custom-classes"
enter-active-class="animate__animated animate__tada"
leave-active-class="animate__animated animate__bounceOutRight"
>
<p v-if="show">hello</p>
</Transition>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(true)
</script>
<style>
@import "https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css";
</style>
1.6. <Transition>
组件生命周期
<Transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@enter-cancelled="onEnterCancelled"
@before-leave="onBeforeLeave"
@leave="onLeave"
@after-leave="onAfterLeave"
@leave-cancelled="onLeaveCancelled"
>
<!-- ... -->
</Transition>
// 在元素被插入到 DOM 之前被调用
// 用这个来设置元素的 "enter-from" 状态
function onBeforeEnter(el) {}
// 在元素被插入到 DOM 之后的下一帧被调用
// 用这个来开始进入动画
function onEnter(el, done) {
// 调用回调函数 done 表示过渡结束
// 如果与 CSS 结合使用,则这个回调是可选参数
done()
}
// 当进入过渡完成时调用。
function onAfterEnter(el) {}
function onEnterCancelled(el) {}
// 在 leave 钩子之前调用
// 大多数时候,你应该只会用到 leave 钩子
function onBeforeLeave(el) {}
// 在离开过渡开始时调用
// 用这个来开始离开动画
function onLeave(el, done) {
// 调用回调函数 done 表示过渡结束
// 如果与 CSS 结合使用,则这个回调是可选参数
done()
}
// 在离开过渡完成、
// 且元素已从 DOM 中移除时调用
function onAfterLeave(el) {}
// 仅在 v-show 过渡中可用
function onLeaveCancelled(el) {}
1.7. transition 常用场景
- 可复用过渡效果
在vue
中过渡效果是可以被封装复用的。要创建一个可被复用的过渡,我们需要为<Transition>
组件创建一个包装组件,并向内传入插槽内容:
<!-- MyTransition.vue -->
<script>
// JavaScript 钩子逻辑...
</script>
<template>
<!-- 包装内置的 Transition 组件 -->
<Transition
name="my-transition"
@enter="onEnter"
@leave="onLeave">
<slot></slot> <!-- 向内传递插槽内容 -->
</Transition>
</template>
<style>
/*
必要的 CSS...
注意:避免在这里使用 <style scoped>
因为那不会应用到插槽内容上
*/
</style>
现在MyTransition
可以在导入后像内置组件那样使用了:
<MyTransition>
<div v-if="show">Hello</div>
</MyTransition>
- 出现时过渡
如果你想在某个节点初次渲染时应用一个过渡效果,你可以添加 appear prop
:
<Transition appear>
...
</Transition>
- 元素间过渡
除了通过v-if / v-show
切换一个元素,我们也可以通过v-if / v-else / v-else-if
在几个组件间进行切换,只要确保任一时刻只会有一个元素被渲染即可:
<Transition>
<button v-if="docState === 'saved'">Edit</button>
<button v-else-if="docState === 'edited'">Save</button>
<button v-else-if="docState === 'editing'">Cancel</button>
</Transition>
- 过渡模式
在之前的例子中,进入和离开的元素都是在同时开始动画的,因此我们不得不将它们设为position: absolute
以避免二者同时存在时出现的布局问题。
然而,很多情况下这可能并不符合需求。我们可能想要先执行离开动画,然后在其完成之后再执行元素的进入动画。手动编排这样的动画是非常复杂的,好在我们可以通过向<Transition>
传入一个mode prop
来实现这个行为:`
<Transition mode="out-in">
...
</Transition>
- 组件间过渡
<Transition>
也可以作用于动态组件之间的切换:
<Transition name="fade" mode="out-in">
<component :is="activeComponent"></component>
</Transition>
- 动态过渡
<Transition>
的props (比如 name)
也可以是动态的!这让我们可以根据状态变化动态地应用不同类型的过渡:
<Transition :name="transitionName">
<!-- ... -->
</Transition>
这个特性的用处是可以提前定义好多组 CSS 过渡或动画的 class
,然后在它们之间动态切换。
2. transition-group组件
<TransitionGroup>
支持和<Transition>
基本相同的 props
、CSS 过渡 class
和 JavaScript 钩子监听器
,但有以下几点区别:
-
默认情况下,它不会渲染一个容器元素。但你可以通过传入
tag prop
来指定一个元素作为容器元素来渲染。 -
过渡模式
在这里不可用,因为我们不再是在互斥的元素之间进行切换。 -
列表中的每个元素都必须有一个独一无二的
key attribute
。 -
CSS
过渡class
会被应用在列表内的元素上,而不是容器元素上。
<transition-group>
组件用于在多个元素插入或删除时添加过渡效果。例如,当我们在一个列表中添加或删除多个项目时,可以使用<transition-group>
组件为这些操作添加一个动画效果。具体用法如下:
2.1. 基本用法
<template>
<div>
<button @click="handleAddLi">显示/隐藏</button>
<transition-group tag="ul">
<li v-for="item in items" :key="item.id">{{ item.text }}</li>
</transition-group>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
const items = reactive([
{
id: 1,
text: 'test1'
},
{
id: 2,
text: 'test2'
}
])
const handleAddLi = () => {
items.push({
id: items.length + 1,
text: 'test' + (items.length + 1)
})
}
</script>
<style scoped>
.v-enter-active,
.v-leave-active {
transition: opacity 2s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
</style>
在上面的代码中,我们使用<transition-group>
组件将一个<ul>
元素包裹起来,并使用v-for
指令渲染一个列表。