Vue3 学习笔记 —— transition、transition-group
Vue3 学习笔记 —— transition、transition-group
目录
1.3.2 使用 GSAP 实现动画效果(Vue 官网推荐)
1. transition 动画组件
1.1 tansition 组件基础用法
transition 组件,用于给包裹元素添加 进入/离开 过渡动画
transition 组件上可以接收 name 属性,用于指定六种动画类名前缀(此处以 fade 为栗子)
- fade-enter-from
- fade-enter-active
- fade-enter-to
- fade-leave-from
- fade-leave-active
- fade-leave-to
动画类名前面的 fade,就是给 transition 指定的 name,动画类名的后面是固定写法
<template>
<div>
<button @click="flag = !flag">
切换
</button>
<!-- 条件渲染 -->
<transition name="fade">
<div v-if="flag" class="my-box"></div>
</transition>
<!-- 条件展示 -->
<transition name="fade">
<div v-show="flag" class="my-box"></div>
</transition>
<!-- 动态组件 -->
<transition name="fade">
<component is="A"></component>
</transition>
</div>
</template>
<script lang="ts" setup>
import { reactive, toRefs, defineComponent } from 'vue';
const flag = ref(true);
</script>
<style lang="scss" scoped>
/* 进入开始 */
.fade-enter-from {
width: 0px;
height: 0px;
background: rgb(255, 153, 0);
transform: rotate(360deg);
}
/* 进入中 */
.fade-enter-active {
transition: all 1s linear;
}
/* 进入完成 */
.fade-enter-to {
width: 200px;
height: 200px;
background: rgb(255, 0, 0);
}
/* 离开开始 */
.fade-leave-from {
width: 200px;
height: 200px;
}
/* 离开中 */
.fade-leave-active {
transition: all 0.5s linear;
}
/* 离开完成 */
.fade-leave-to {
width: 0px;
height: 0px;
}
</style>
1.2 自定义类名,并使用 animate.css
1.2.1 自定义类名
transition 组件定义了以下 props,用于接收:
- 自定义过渡类名
- 自定义过渡时间(可以直接传入毫秒数,也可以分别定义进入或离开时的毫秒数)
举个栗子~~
<!-- :duration="1000" -->
<transition
:enter-from-class="'classA'"
:enter-active-class="'classB'"
:enter-to-class="'classC'"
:leave-from-class="'classD'"
:leave-active-class="'classE'"
:leave-to-class="'classF'"
:duration="{ enter: 500, leave: 800 }"
>
<component is="A"></component>
</transition>
1.2.2 animate.css 动画库
通过 transition 自定义 class,结合 animate.css 动画库,就能实现多种动画效果
// 安装 animate.css
npm install animate.css --save
yarn add animate.css
// 在 main.ts 中引入 animate.css
import 'animate.css'
举个栗子~~
<transition
leave-active-class="animate__animated animate__bounceInLeft"
enter-active-class="animate__animated animate__bounceInRight"
>
<div v-if="flag" class="my-box"></div>
</transition>
注意:一定要添加类名前缀 animate__animated,否则动画效果无法生效
1.3 transition 生命周期,使用 GSAP
1.3.1 transition 生命周期
transition 的生命周期,相对于 props 多了两条:
- 显示过渡打断
- 离开过渡打断
生命周期具体包含以下几种:
@before-enter="beforeEnter" --- 对应 enter-from
@enter="enter" --- 对应 enter-active
@after-enter="afterEnter" --- 对应 enter-to
@enter-cancelled="enterCancelled" --- 显示过渡打断(多出来的)
@before-leave="beforeLeave" --- 对应 leave-from
@leave="leave" --- 对应 leave-active
@after-leave="afterLeave" --- 对应 leave-to
@leave-cancelled="leaveCancelled" --- 离开过渡打断(多出来的)
注意事项:
- 每个生命周期函数接收一个 el 参数,标识执行过渡动画的 DOM 元素
- enter / leave 函数除了 el 参数,还接收 done 参数,标识动画执行完成(举个栗子:enter 动画执行过程为 3s,加了 done 函数后,三秒之后才执行 after-enter,不加则 同步执行 两个函数)
- 只用 JavaScript 过渡时,在 enter 和 leave 钩子中,必须使用 done 进行回调
- enter-cancelled / leave-cancelled 函数指 当元素在执行完动画之前,就已经被按钮控制隐藏了,此时就会调用打断函数
<transition
:before-enter="enterFrom"
:enter="enterActive"
:after-enter="enterTo"
:enter-cancelled="enterCancel"
:before-leave="leaveFrom"
:leave="leaveActive"
:after-leave="leaveTo"
:leave-cancelled="leaveCancel"
>
<component is="A"></component>
</transition>
// before-enter
const enterFrom = (el: Element) => {
console.log('进入之前');
};
/**
* enter
* @param el 执行过渡动画的 DOM 元素
* @param done 标识动画执行完成
*/
const enterActive = (el: Element, done: Function) => {
console.log('过渡曲线');
setTimeout(() => {
// 三秒后,此动画执行完毕,可以打印下面的 过渡完成 了
done();
}, 3000);
};
// after-enter
const enterTo = (el: Element) => {
console.log('过渡完成');
};
// enter-cancelled
const enterCancel = (el: Element) => {
console.log('过渡效果被打断');
console.log('在 3s 内过渡效果还没完成,元素就隐藏了,此时就会执行被打断函数');
};
1.3.2 使用 GSAP 实现动画效果(Vue 官网推荐)
// 使用 cdn 的方式引入
https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.3/gsap.min.js
// 使用 npm 进行安装
npm install gsap
注意事项:
- gsap.set —— 动画初始状态
- gsap.to —— 动画最终状态
- onComplete —— gsap 中,过渡完成的回调函数
- done 函数 ts 类型报错 —— 将 Function 类型替换为 gsap.Callback 即可
<transition
:before-enter="enterFrom"
:enter="enterActive"
:leave="leaveActive"
>
<component is="A"></component>
</transition>
import gsap from 'gsap';
// before-enter
const enterFrom = (el: Element) => {
console.log('进入之前');
gsap.set(el, {
width: 0,
height: 0,
});
};
/**
* enter
* @param el 执行过渡动画的 DOM 元素
* @param done 标识动画执行完成
* @decription 关于 done 类型的报错,使用 gsap.Callback 替换 Function
*/
const enterActive = (el: Element, done: gsap.Callback) => {
console.log('过渡曲线');
gsap.to(el, {
width: 200,
height: 200,
// 过渡完成的回调函数
onComplete: done,
});
};
/**
* leave
* @param el 执行过渡动画的 DOM 元素
* @param done 标识动画执行完成
* @decription 关于 done 类型的报错,使用 gsap.Callback 替换 Function
*/
const leaveActive = (el: Element, done: gsap.Callback) => {
console.log('过渡曲线');
gsap.to(el, {
width: 0,
height: 0,
// 过渡完成的回调函数
onComplete: done,
});
};
1.4 appear
appear 属性 —— 设置 页面加载完成后,首次、立刻执行的动画
appear 有三个状态,可以接收自定义类名(可以结合 animate.css 使用)
<template>
<transition
appear
appear-from-class="appear-from"
appear-active-class="appear-active"
appear-to-class="appear-to"
>
<component is="A"></component>
</transition>
</template>
...
<style lang="scss" scoped>
.appear-from {
width: 0px;
height: 0px;
}
.appear-active {
transition: all 0.5s linear;
}
.appear-to {
width: 200px;
height: 200px;
}
</style>
2. transition-group 动画列表
参考视频(强烈推荐,小满讲的非常清楚)
2.1 列表项过渡
transition-group 组件的 props、生命周期 和 transition 组件一模一样
注意事项:
- transition-group 接收 tag 属性,用于自动生成一个 包裹列表项的 DOM 元素
- transition-group 内部的元素,一般是循环出来的列表项,一定要使用 key 标识唯一值
- transition-group 的样式会在列表项中生效,而不是列表容器
<template>
<button @click="addItem">
新增列表项
</button>
<button @click="removeItem">
删除列表项
</button>
<!-- 过渡列表 -->
<div class="list-wrap">
<transition-group
tag="section"
enter-active-class="animate__animated animate__bounceIn"
leave-active-class="animate__animated animate__hinge"
>
<div v-for="item in list" :key="item" class="list-item">
{{ item }}
</div>
</transition-group>
</div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue';
import 'animate.css';
const list = reactive<number[]>([1, 2, 3, 4, 5, 6]);
const addItem = () => {
list.push(list.length + 1);
};
const removeItem = () => {
list.pop();
};
</script>
<style lang="scss" scoped>
.list {
&-wrap {
display: flex;
flex-wrap: wrap;
word-break: break-all;
border: 1px solid #D7D7D7;
}
&-item {
margin: 10px;
font-size: 20px;
}
}
</style>
2.2 平面过渡
2.2.1 初始化数组的小技巧
如果使用 new Array(81) 直接生成数组,那么不会初始化数组的每一项
如果使用 apply 生成数组,则初始化时,会自动填充数组每一项为 undefined
2.2.2 安装 lodash ts 声明文件
执行下方命令安装 lodash
npm i --save lodash
安装完毕后,可能出现报错,因为没有安装 ts 类型声明文件,执行下方命令安装
npm install @types/lodash -D
lodash.shuffle —— 将数组内的元素,随机打乱顺序
2.2.3 生成平面过渡的表格
场景描述:生成9行9列的表格,点击按钮后,实现单元格平面移动的效果
<template>
<div>
<button @click="shuffleArray">
随机打乱数组内元素的顺序
</button>
<transition-group tag="ul" class="list-wraps">
<!-- 一定要绑定 key,否则会不生效 -->
<li v-for="item in testList" :key="item.id" class="list-cell">
{{ item.number }}
</li>
</transition-group>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
// 别忘记装 ts 声明文件:npm install @types/lodash -D
import _ from 'lodash';
/*
* [
* { id: 1, number: 1 },
* { id: 8, number: 8 },
* { id: 18, number: 1 },
* { id: 27, number: 1 },
* ]
*/
const testList = ref(
Array.apply(null, { length: 81 } as number[]).map((_, index) => ({
id: index,
// 每 9 个为一组
number: (index % 9) + 1,
})),
);
/**
* 将数组内的元素,随机打乱顺序
*/
const shuffleArray = () => {
testList.value = _.shuffle(testList.value);
};
</script>
<style scoped lang="less">
.list-wraps {
display: flex;
flex-wrap: wrap;
// 每 9 个一排
width: calc(25px * 10 + 9px);
.list-cell {
display: flex;
justify-content: center;
align-items: center;
width: 25px;
height: 25px;
border: 1px solid #dcdcdc;
list-style-type: none;
}
}
</style>
2.3 状态过渡
举个栗子:数字从 9999 变成 1 时,添加滚动状态过渡的效果
再举个栗子:背景色从 红色 变成 蓝色 时,添加背景色过渡的效果
<template>
<div>
<!-- step 每次数字变动大小为 20 -->
<input v-model="state.inputNumber" type="number" step="20" />
<!-- 展示过渡效果的值 -->
<div>{{ state.showTransitionNumber.toFixed(0) }}</div>
</div>
</template>
<script setup lang='ts'>
import { reactive, watch } from 'vue';
import gsap from 'gsap';
const state = reactive({
// 使用 input 改变的值
inputNumber: 0,
// 展示过渡效果的值
showTransitionNumber: 0,
});
/**
* 当 input 数字改变时,调整 展示过渡效果的值
*/
watch(() => state.inputNumber, (newVal) => {
gsap.to(state, {
// 过渡时间
duration: 1,
// 将 展示过渡效果的值 从原来的值,替换为 使用 input 改变的值
showTransitionNumber: newVal,
});
});
</script>
更多推荐
所有评论(0)