Transition && TransitionGroup
动画组件
触发条件:
- v-if
- v-show
- component 切换的动态组件
- 改变特殊的key
css过渡class
v-enter-from进入动画的起始状态v-enter-active用来定义进入动画的持续时间、延迟与速度曲线类型v-enter-to进入动画的结束状态v-leave-from离开动画的起始状态v-leave-active用来定义离开动画的持续时间、延迟与速度曲线类型。v-leave-to离开动画的结束状态
为过渡效果命名 name=xxx,name也可以是一个变量,实现动态过渡
<Transition name="slide-fade">
<p v-if="show">hello</p>
</Transition>
/*
进入和离开动画可以使用不同
持续时间和速度曲线。
*/
.slide-fade-enter-active {
transition: all 0.3s ease-out;
}
.slide-fade-leave-active {
transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateX(20px);
opacity: 0;
}
与css原生动画一起使用
<Transition name="bounce">
<p v-if="show" style="text-align: center;">
Hello here is some bouncy text!
</p>
</Transition>
.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1);
}
}
自定义过渡class,比如在使用Animate.css插件库的时候
enter-from-classenter-active-classenter-to-classleave-from-classleave-active-classleave-to-class
<!-- 假设你已经在页面中引入了 Animate.css -->
<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>
可复用过渡效果
<!-- 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>
<div v-if="show">Hello</div>
</MyTransition>
某个节点初次渲染时应用一个过渡效果,添加appear属性
<Transition appear>
...
</Transition>
元素间过渡 && 过渡模式
因为进入和离开的元素是在同时开始动画的,所以一般都用 position:absolute 来避免二者同时存在出现布局问题;
如果想要先执行离开动画,在其完成后再执行元素的进入动画可以给Transtion 添加 mode=out-in
<Transition mode="out-in">
<button v-if="docState === 'saved'">Edit</button>
<button v-else-if="docState === 'edited'">Save</button>
<button v-else-if="docState === 'editing'">Cancel</button>
</Transition>
组件间过渡
<Transition name="fade" mode="out-in">
<component :is="activeComponent"></component>
</Transition>
js动画钩子
<Transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@enter-cancelled="onEnterCancelled"
@before-leave="onBeforeLeave"
@leave="onLeave"
@after-leave="onAfterLeave"
@leave-cancelled="onLeaveCancelled"
>
<!-- ... -->
</Transition>
关于动画性能
transform和opacity属性制作动画非常高效,height和margin这种则会触发布局变动,耗费较高
TransitionGroup 用于对 v-for 列表中的元素或组件的插入、移除和顺序改变添加动画效果。
//class 会被应用在列表内的元素上,而不是容器元素上。
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item">
{{ item }}
</li>
</TransitionGroup>
.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;
}
KeepAlive
KeepAlive 用来缓存被移除的组件实例,默认会缓存内部的所有组件实例
它会根据组件的 name 选项进行匹配
注:<script setup> 的单文件组件会自动根据文件名生成对应的 name 选项
- include 包含组件
- exclude 不包含组件
<!-- 以英文逗号分隔的字符串 -->
<KeepAlive include="a,b">
<component :is="view" />
</KeepAlive>
<!-- 正则表达式 (需使用 `v-bind`) -->
<KeepAlive :include="/a|b/">
<component :is="view" />
</KeepAlive>
<!-- 数组 (需使用 `v-bind`) -->
<KeepAlive :include="['a', 'b']">
<component :is="view" />
</KeepAlive>
也可以和router-view一起使用
<router-view v-slot="{ Component }">
//max设置最大缓存实例
<keep-alive :max="10" include="helloWord,helloVue">
<component :is="Component" />
</keep-alive>
</router-view>
缓存实例的生命周期
被keepAlive缓存的组件被移除时变为不活跃状态onDeactivated(),重新插入到DOM树时变为被激活 onActivated()
onActivated在组件挂载时也会调用,并且onDeactivated在组件卸载时也会调用。- 这两个钩子不仅适用于
<KeepAlive>缓存的根组件,也适用于缓存树中的后代组件。
Teleport
将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。
常见的例子就是在一个组件内部创建一个全屏的模态框的时候,逻辑写在同一个组件内,
<button @click="open = true">Open Modal</button>
//传入动态的disabled 来处理是行内组件还是浮层
<Teleport to="body" :disabled="isMobile">
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">Close</button>
</div>
</Teleport>
disabled为true的时候 就变成行内组件