Vue 提供了一些内置组件和对应的 API 来完成动画,利用它们可以方便地实现动画效果。
<transition>
内置组件:
Vue 提供了 <transition>
内置组件,可以给任意元素或组件添加进入/离开时的动画效果。在条件渲染、动态组件、改变 key 属性时将会触发。
主要针对单个元素或组件。
transition 过渡动画:
<!-- 给 <div> 元素的显示与隐藏添加过渡动画 -->
<template><!-- 2. 使用 <transition> 包裹想要添加动画的元素,Vue 在恰当的时机将编写好的类自动添加、移除 --><transition><div v-if="isShow">Hello Vue</div></transition><button @click="handleChange">切换</button>
</template><script setup>
import {ref} from 'vue'
const isShow = ref(false)
const handleChange = () => {isShow.value = !isShow.value
}
</script><style scoped>
/* 1. 编写想要的动画的类 */
/* 进入前的状态 */
.v-enter-from,
/* 离开后的状态 */
.v-leave-to {opacity: 0;
}/* 进入后的状态 */
.v-enter-to,
/* 离开前的状态 */
.v-leave-from {opacity: 1;
}/* 进入时的效果 */
.v-enter-active,
/* 离开时的效果 */
.v-leave-active {transition: opacity 1s ease;
}
</style>
animation 序列帧动画:
<!-- 给 <div> 元素的显示与隐藏添加 animation 动画 -->
<template><!-- 2. 使用 <transition> 包裹想要添加动画的元素,Vue 在恰当的时机将编写好的类自动添加、移除 --><transition><div v-if="isShow">Hello Vue</div></transition><button @click="handleChange">切换</button>
</template><script setup>
import {ref} from 'vue'
const isShow = ref(false)
const handleChange = () => {isShow.value = !isShow.value
}
</script><style scoped>
/* 1. 编写想要的动画的类 */
@keyframes enterAnimation {0% {transform: scale(0);}50% {transform: scale(2);}100% {transform: scale(1);}
}/* 进入时的效果 */
.v-enter-active {animation: enterAnimation 1s ease;
}@keyframes leaveAnimation {0% {transform: scale(1);}50% {transform: scale(2);}100% {transform: scale(0);}
}/* 离开时的效果 */
.v-leave-active {animation: leaveAnimation 1s ease;
}
</style>
<transition>
组件的原理:
Vue 并没有编写好动画的类,只是会在恰当的时机将开发者编写好的类自动添加、移除。
当插入或者删除包含在 <transition>
组件中的元素时,Vue 会做以下处理:
- 自动嗅探目标元素是否应用了 CSS 动画,如果有的话,那么将会在恰当的时机自动添加/移除 CSS 类名。
- 如果
<transition>
组件提供了 JavaScript 钩子函数,那么这些钩子函数将会在恰当的时机被调用。 - 如果没有检测到 CSS 动画并且也没有找到 JavaScript 钩子函数,那么 DOM 的插入、删除操作将会立即执行。
<transition>
组件的属性:
- name:动画的 class 类名的前缀。
- duration:显式地设置动画的持续时间。
- appear:首次渲染时是否采用动画。默认首次渲染是没有动画的。
- type:当同时使用过渡动画和序列帧动画时,以谁的时间为动画的结束时刻。属性值可以为 transition 或者 animation。当不设置type时,默认会取 transitioned 和 animationed 两者更长的为结束时刻。
- mode:当一个动画在两个元素之间切换时,如果不希望同时执行进入动画和离开动画,俺么可以设置动画的过渡模式。属性值可以为
in-out
,新元素先过渡进入,完成之后当前元素再过渡离开;out-in
:当前元素先过渡离开,新元素再过渡进入。<template><!-- 如果不设置 mode 过渡属性,那么一个元素显示、一个元素消失将会同时执行动画。设置 mode="out-in" 之后,Hello Vue 会先消失,然后你好,世界再显示 --><transition mode="out-in"><div v-if="isShow">Hello Vue</div><div v-else> 你好,世界</div></transition><button @click="handleChange">切换</button></template><script setup>import {ref} from 'vue'const isShow = ref(true)const handleChange = () => {isShow.value = !isShow.value}</script><style scoped>.v-enter-from, .v-leave-to {opacity: 0;}.v-enter-to,.v-leave-from {opacity: 1;}.v-enter-active,.v-leave-active {transition: opacity 1s ease;}</style>
动画的 class 类:
v-enter-from
:进入动画的起始状态。在元素被插入之前添加,在元素插入完成后的下一帧移除。v-enter-active
:进入动画的生效状态。应用于整个进入动画阶段,在元素被插入之前添加,在动画完成之后移除。v-enter-to
:进入动画的结束状态。在元素被插入完成后的下一帧添加,在动画完成之后移除。v-leave-from
:离开动画的起始状态。在离开动画被触发时立刻添加,下一帧被移除。v-leave-active
:离开动画的生效状态。应用于整个离开动画阶段,在离开动画被触发时立刻添加,在动画完成之后移除。v-leave-to
:离开动画的结束状态。在离开动画被触发后的下一帧添加,在动画完成之后移除。
动画的 class 类的命名规则:
- 如果使用的是一个没有 name 的
<transition>
,那么所有的 class 是以v-
作为默认前缀。 - 如果给
<transition>
添加了 name 属性,那么所有的 class 会以 name 属性值做前缀。例如<transition name=''fade>
,那么所有的 class 以fase-
为前缀。
<transition-group>
内置组件:
Vue 提供了 <transition-group>
内置组件,可以为列表添加、删除数据时添加动画效果。
主要针对列表元素或组件。
<!-- 列表添加、删除元素时,添加、删除的元素将会运用动态效果 --><template><!-- 默认情况下,<transition-group> 不会渲染成一个元素的包裹器,可以通过指定 tag 属性将其渲染为想要的元素 --><transition-group tag="div"><!-- 内部元素总是需要提供唯一的 key 属性。CSS 动画的类将会应用在内部的元素上,而不是外面的包裹容器上 --><template v-for="item in nums" :key="item"><div>{{ item }}</div></template></transition-group><button @click="handleAdd">插入</button><button @click="handlDelete">删除</button></template><script setup>import {ref} from 'vue'const nums = ref([0, 1, 2, 3, 4, 5])const randomIndex = () => {return Math.floor(Math.random() * nums.value.length)}const handleAdd = () => {nums.value.splice(randomIndex(), 0, nums.value.length)}const handlDelete = () => {nums.value.splice(randomIndex(), 1)}</script><style scoped>.v-enter-from, .v-leave-to {opacity: 0;transform: translateY(30px);}.v-enter-to,.v-leave-from {opacity: 1;transform: translateY(0);}.v-enter-active,.v-leave-active {transition: opacity 1s ease;}</style>
此时,列表添加、删除的元素是有动画的,但是由于添加或者删除导致的其他需要移动的元素是没有动画的。可以使用一个新增的 v-move
的 class 来完成动画,它会在元素改变位置的过程中应用。
<transition-group>
组件的属性:
- 除了 mode 过渡模式不可用外,其他
<transition>
组件的属性都可用。 - tag:默认情况下,
<transition-group>
不会渲染成一个元素的包裹器,可以通过指定 tag 属性将其渲染为想要的元素。
动画的 class 类:
<transition>
中动画的 class 类都可用。v-move
:会在元素改变位置的过程中应用。
上面的示例中,列表添加、删除的元素是有动画的,但是由于添加或者删除而导致的其他需要移动的元素是没有动画的。可以使用 新增的<template><transition-group tag="div"><template v-for="item in nums" :key="item"><div>{{ item }}</div></template></transition-group><button @click="handleAdd">插入</button><button @click="handlDelete">删除</button></template><script setup>import {ref} from 'vue'const nums = ref([0, 1, 2, 3, 4, 5])const randomIndex = () => {return Math.floor(Math.random() * nums.value.length)}const handleAdd = () => {nums.value.splice(randomIndex(), 0, nums.value.length)}const handlDelete = () => {nums.value.splice(randomIndex(), 1)}</script><style scoped>.v-enter-from, .v-leave-to {opacity: 0;transform: translateY(30px);}.v-enter-to,.v-leave-from {opacity: 1;transform: translateY(0);}.v-enter-active,.v-leave-active,/* 为其他移动的元素添加动画 */.v-move {transition: all 3s ease;}/* 元素离开时设置绝对定位,否则的话,离开动画的过程中,被删除元素仍然占据位置,导致其他需要移动的元素无法运用动画 */.v-leave-active {position: absolute;}</style>
v-move
的 class 来完成动画。