一 transition基础用法
<!-- 自定义类型名称 enter-to-class enter-active-class enter-from-class -->
<template>
<div class="content">
<button @click="flag = !flag">switch</button>
<!-- 自定义类型名称 enter-to-class enter-active-class enter-from-class -->
<transition name="fade">
<div class="box" v-if="flag"></div>
</transition>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const flag = ref<boolean>(true)
</script>
<style lang="less" scoped>
.fade-enter-from {
width: 0;
height: 0;
transform: rotate(360deg);
}
.fade-enter-active {
transition: all 1.5s ease;
}
.fade-enter-to {
width: 200px;
height: 200px;
}
.fade-leave-from {
width: 200px;
height: 200px;
transform: rotate(360deg);
}
.fade-leave-active {
transition: all 2s ease;
}
.fade-leave-to {
width: 0;
height: 0;
}
.box {
width: 200px;
height: 200px;
background: red;
}
.content {
position: absolute;
left: 10px;
top: 10px;
background: blue;
}
</style>
二transition和animate结合
自定义过度类
enter-from-class enter-active-class enter-to-class
leave-from-class leave-active-class leave-to-class
可以自定义class结合动画库animate.css
样式使用less
npm install less less-loader -D
动画animate.css安装
npm install animate.css --save
import animated from 'animate.css'
Vue.use(animated)
gsap安装
npm install gsap -S
<template>
<div class="content">
<button @click="flag = !flag">switch</button>
<!-- :duration="500" :duration="{ enter: 50, leave: 500 }" -->
<transition
:duration="{ enter: 50, leave: 500 }"
enter-active-class="animate__animated animate__fadeIn"
leave-active-class="animate__animated animate__fadeOut">
<div class="box" v-if="flag"></div>
</transition>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import 'animate.css'
const flag = ref<boolean>(true)
</script>
<style lang="less" scoped>
.box {
width: 200px;
height: 200px;
background: red;
}
.content {
position: absolute;
left: 10px;
top: 10px;
}
</style>
三 tranisition生命周期和gsap
<template>
<div class="content">
<button @click="flag = !flag">switch</button>
<!-- :duration="500" :duration="{ enter: 50, leave: 500 }" -->
<transition
@before-enter="EnterFrom"
@enter="EnterActive"
@after-enter="EnterTo"
@enter-cancelled="EnterCancel"
@before-leave="LeaveFrom"
@leave="Leave"
@after-leave="LeaveTo"
@leave-cancelled="LeaveCancel">
<div class="box" v-if="flag"></div>
</transition>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import 'animate.css'
const flag = ref<boolean>(true)
const EnterFrom = (el:Element) => {
console.log('进入之前')
}
const EnterActive = (el:Element, done: Function) => {
console.log('过度曲线')
setTimeout(() => {
done()
}, 3000)
}
const EnterTo = (el:Element) => {
console.log('过度完成')
}
const EnterCancel = (el:Element) => {
console.log('过度效果被打断')
}
const LeaveFrom = (el:Element) => {
console.log('离开之前')
}
const Leave = (el:Element, done:Function) => {
console.log('离开过度曲线')
setTimeout(() => {
done()
}, 5000)
}
const LeaveTo = (el:Element) => {
console.log('离开完成')
}
const LeaveCancel = (el:Element) => {
console.log('离开过度曲线被打断-----------')
}
</script>
<style lang="less" scoped>
.box {
width: 200px;
height: 200px;
background: red;
}
.content {
position: absolute;
left: 10px;
top: 10px;
}
</style>
使用gsap
<template>
<div class="content">
<button @click="flag = !flag">switch</button>
<!-- :duration="500" :duration="{ enter: 50, leave: 500 }" -->
<transition
@before-enter="EnterFrom"
@enter="EnterActive"
@leave="Leave">
<div class="box" v-if="flag"></div>
</transition>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import gsap from 'gsap'
const flag = ref<boolean>(true)
const EnterFrom = (el:Element) => {
gsap.set(el, {
width: 0,
height: 0,
})
}
const EnterActive = (el:Element, done: gsap.Callback) => {
gsap.to(el, {
width: 200,
height: 200,
onComplete: done
})
}
const Leave = (el:Element, done: gsap.Callback) => {
gsap.to(el, {
width: 0,
height: 0,
onComplete: done
})
}
</script>
<style lang="less" scoped>
.box {
width: 200px;
height: 200px;
background: red;
}
.content {
position: absolute;
left: 10px;
top: 10px;
}
</style>
四 appear
<template>
<div class="content">
<button @click="flag = !flag">switch</button>
<!-- appear进入页面时候触发效果 -->
<transition
appear
appear-active-class="animated__animated animate__hinge">
<div class="box" v-if="flag"></div>
</transition>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import 'animate.css'
const flag = ref<boolean>(true)
</script>
<style lang="less" scoped>
.box {
width: 200px;
height: 200px;
background: red;
}
.content {
position: absolute;
left: 10px;
top: 10px;
}
</style>
五transition-group
<template>
<div class="content">
<button @click="add">add</button><button @click="pop">pop</button>
<div class="wraps">
<transition-group
enter-active-class="animate__animated animate__bounceIn"
leave-active-class="animate__animated animate__bounceOut">
<div class="item" v-for="(item, index) in list" :key="index">{{ item }}</div>
</transition-group>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import 'animate.css'
const list = reactive<number[]>([1, 2, 3, 4, 5])
const add = () => {
list.push(list.length + 1)
}
const pop = () => {
list.pop()
}
</script>
<style lang="less" scoped>
.wraps {
display: flex;
flex-wrap: wrap;
word-break: break-all;
border: 1px solid #ccc;
.item {
margin: 10px;
font-size: 30px;
}
}
</style>
六 平面动画效果
安装lodash
npm install lodash -S
npm install @types/lodash -D
<template>
<div>
<button @click="random">random</button>
<transition-group class="wraps" tag="div" move-class="mmm">
<div class="items" v-for="(item, index) in list" :key="item.id">
{{ item.number }}
</div>
</transition-group>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import _ from 'lodash'
let list = ref(Array.apply(null, { length: 81 } as number[]).map((_, index) => {
return {
id: index,
number: (index % 9) + 1
}
}))
const random = () => {
list.value = _.shuffle(list.value)
}
</script>
<style lang="less" scoped>
.wraps {
display: flex;
flex-wrap: wrap;
width: calc(25px * 10 + 9px);
.items {
width: 25px;
height: 25px;
border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
}
}
.mmm {
transition: all 1s;
}
</style>
七 状态过度
<template>
<div>
<input v-model="num.current" step="20" type="number"/>
<div>
{{ num.tweendNumber.toFixed(0) }}
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, watch } from 'vue'
import gsap from 'gsap'
const num = reactive({
current: 0,
tweendNumber: 0
})
watch(() => num.current, (newVal, oldVal) => {
gsap.to(num, {
duration: 1,
tweendNumber: newVal
})
})
</script>
<style lang="less" scoped>
</style>