想要制作基于状态变化的过渡,使用vue内置组件、Class、动画库来快速实现;
<Transition>
🔗 会在单个元素或组件进入和离开 DOM 时应用动画;<TransitionGroup>
🔗 会在一个v-for
列表中的元素或组件被插入,移动,或移除时应用动画;
下面使用Vue3的代码对DOM的width
、height
属性进行过渡的不同实现方式
1、<transition>
标签
使用 name
属性 来定义class 来实现DOM的属性的过渡
vue3
<template>
<div>
<button @click="flag = !flag">switch</button>
<!-- 用法1 name属性定义class-->
<transition name="fade">
<div v-if="flag" class="box">name属性定义class</div>
</transition>
</div>
</template>
<script setup lang='ts'>
import{ref} from 'vue'
const flag = ref<boolean>(true)
</script>
<style scoped lang="scss">
.box{
width: 200px;
height: 200px;
background-color: red;
}
.fade-enter-from { // 进入 从XX 开始
width: 0;
height: 0;
}
.fade-enter-active {
// 过程
transition: all 1.5s ease;
}
.fade-enter-to { // 进入 到 XX 结束
width: 200px;
height: 200px;
transform: scale(1.2); // 放大1.2倍
}
.fade-leave-from { // 离开 从XX 开始
width: 200px;
height: 200px;
}
.fade-leave-active {
// 过程
transition: all 1.5s ease;
}
.fade-leave-to { // 离开 到 XX 结束
width: 0;
height: 0;
}
</style>
页面效果:
可以通过name属性,绑定指定name的class, 灵活定义过渡的进入
和离开
时的效果;
上面方式缺点是class.xxx-enter-from
-enter-from
部分是固定的, 如果想要定义整个class名,可以使用<Transition>
另外属性;
进入:enter-from-class
、enter-active-class
、enter-to-class
、
离开:leave-from-class
、leave-active-class
、leave-to-class
vue3
<template>
<transition
enter-from-class="dada-enter-from"
enter-active-class="dada-enter-active"
enter-to-class="dada-enter-to"
leave-from-class="dada-leave-from"
leave-active-class="dada-leave-active"
leave-to-class="dada-leave-to">
<div v-if="flag" class="box">自定义类名</div>
</transition>
</template>
...
<style scoped lang="scss">
dada-enter-from {
width: 0;
height: 0;
}
.dada-enter-active {
// 过程
transition: all 1.5s ease;
}
.dada-enter-to { // 进入 到 XX 结束
width: 200px;
height: 200px;
transform: scale(1.2); // 放大1.2倍
}
.dada-leave-from {
width: 200px;
height: 200px;
}
.dada-leave-active {
// 过程
transition: all 1.5s ease;
}
.dada-leave-to { // 离开 到 XX 结束
width: 0;
height: 0;
}
</style>
页面效果:同上
<transition>
+ 动画库 animate.css
安装: npm install animate.css --save
或yarn add animate.css
vue3
<transition
:duration="1000"
enter-active-class="animate__animated animate__flipInX"
leave-active-class="animate__animated animate__fadeOutDown">
<div v-if="flag" class="box font-12">结合第三方类库 animate.css</div>
</transition>
<script setup lang='ts'>
import 'animate.css'
</script>
属性duration:number|{enter:number, leave:number}
是指动画时长;如果进入
和离开
定义相同时长,值可定义number类型,如果进入
和离开
定义不同时长,值可定义object类型;
注意,使用class时不要漏加特定classanimate__animated
,
页面效果:
使用第三方CSS动画库,过渡效果丰富,减少自己写CSS代码,直接添加对应效果的class即可;
丰富有趣的交互效果,往往只有class是不够的,还需要通过JS代码控制动画来实现;
想要通过 Javascript来控制过渡动画,首先理解过渡的时机,动画分为进入
和离开
,进入
有:进入前
、进入
、进入后
,同样离开
: 离开前
、离开
、离开后
,那么在不同时机中,触发JavaScript 逻辑即可;
<transition>
对应的事件:
@before-enter
:进入之前@before-leave
:离开之前@enter
:进入时@leave
:离开时@after-enter
:进入之后@after-leave
:离开之后@enter-cancelled
:进入中断@leave-cancelled
(v-show
only):离开中断
template
<template>
<transition
@before-enter="EnterFrom"
@enter="EnterActive"
@after-enter="EnterTo"
@enter-cancelled="EnterCancel"
@before-leave="LeaveFrom"
@leave="LeaveActive"
@after-leave="LeaveTo"
@leave-cancelled="LeaveCancel" >
<div v-if="flag" class="box">8个 生命周期</div>
</transition>
</template>
<script setup lang='ts'>
// 进入
const EnterFrom = (el:Element) => {
console.log('动画进入之前EnterFrom');
}
const EnterActive = (el:Element, done: gsap.Callback) => {
console.log('进入时 EnterActive');
}
const EnterTo = (el:Element) => {
console.log(el,'动画进入之后 EnterTo');
}
const EnterCancel = (el:Element) => {
console.log(el,'动画进过渡效果 被打断时 EnterCancel');
}
// 离开
// el DOM 节点
const LeaveFrom = (el:Element) => {
console.log(el, '动画离开之前LeaveFrom');
}
const LeaveActive = (el:Element, done:Function) => {
console.log(el,'离开时 LeaveActive');
done()
}
const LeaveTo = (el:Element) => {
console.log(el,'动画离开之后 LeaveTo');
}
const LeaveCancel = (el:Element) => {
console.log(el,'动画离开过渡效果 被打断时------');
}
</script>
过渡进入时触发:
过渡离开时触发: 过渡中断是什么时候出发呢,当进入过程中立马切换为离开时就会触发中断的函数了;当理解了出发函数钩子的时机,可以结合优秀的动画库,精准的实现效果;
2、<transition-group>
标签
单节点动画可以使用<transition>
,多节点可以使用 <transition-group>
;
特点:
- 默认情况下 它不会渲染一个包裹元素,但是可以通过tag attribute 指定渲染一个元素,
<transition-group tag="div">
或<transition tag="section">
实际生成DOM标签div
或section
包一层; - 过渡模式下不可用, 因为我们不再相互切换特有的元素
- 内部元素 总是需要提供一个唯一的 key attribute值
- CSS过渡的类型将会应用在内部的元素中,而不是这个组/容器本身
列表的移动过渡示例:
vue3
<template>
<!-- 列表的移动过度示例
技术点: <transition-group> 组件还有一个特殊之处除了进入和离开,transition-group还可以为定位的改变添加动画
第三方库: lodash npm install lodash --S 注意在ts 下 还需要安装类型声明文件库 npm i --save-dev @types/lodash
-->
<div>
<button @click="random">random</button>
<transition-group move-class="move" class="wrap" tag="div">
<div class="item" v-for="item in list" :key="item.id">{{ item.number }}</div>
</transition-group>
</div>
</template>
<script setup lang='ts'>
import {ref} from 'vue'
import _ from 'lodash' // 需要安装声明文件 npm i -D @types/lodash
let list = ref(Array.apply(null, {length:81} as number[]).map((_, index) => {
return {
id: index,
number: (index % 9) + 1
}
}))
console.log(list, 'list');
const random = () => {
list.value = _.shuffle(list.value)
}
</script>
<style scoped lang="scss">
.wrap {
display: flex;
flex-wrap: wrap;
width: calc(25px * 9 + 9px);
.item {
width: 25px;
height: 25px;
border: 1px solid #ccc;
display: flex;
justify-self: center;
align-items: center;
}
}
.move {
transition: all 1s;
}
</style>
状态的过渡:
vue3
<template>
<input type="number" step="20" v-model="num.current">
<div style="font-size: 30px; margin-left: 20px;">{{ num.tweenedNumber.toFixed() }}
</div>
</template>
<script setup lang='ts'>
import {reactive, watch} from 'vue'
import gsap from 'gsap'
const num = reactive({
current: 0,
tweenedNumber:0
})
watch(() => num.current, (newVal) =>{
gsap.to(num, {
duration: 1,
tweenedNumber: newVal
})
})
</script>
3、总结
主要理解<Transition>
、<TransitionGroup>
,同时结合动画库来实现过渡效果;