1. 基础过渡动画
javascript
<template>
<!--
transition 组件是 Vue 提供的内置组件
name 属性定义了过渡类名的前缀
-->
<transition name="fade">
<div v-if="show" class="box">Hello</div>
</transition>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(false)
</script>
<style>
/* 进入和离开的过渡状态 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
/* 进入前和离开后的状态 */
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
/* 进入后和离开前的状态 */
.fade-enter-to,
.fade-leave-from {
opacity: 1;
}
</style>
2. 自定义过渡类名
javascript
<template>
<!--
使用自定义类名,可以配合第三方动画库使用
比如 Animate.css
-->
<transition
enter-active-class="animate__animated animate__fadeIn"
leave-active-class="animate__animated animate__fadeOut"
>
<div v-if="show">自定义动画</div>
</transition>
</template>
<script setup>
import 'animate.css'
import { ref } from 'vue'
const show = ref(false)
</script>
3. 过渡动画钩子
javascript
<template>
<transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@before-leave="onBeforeLeave"
@leave="onLeave"
@after-leave="onAfterLeave"
>
<div v-if="show" class="box">动画钩子</div>
</transition>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(false)
// 进入过渡前
const onBeforeEnter = (el) => {
el.style.opacity = 0
}
// 进入过渡中
const onEnter = (el, done) => {
// 触发回流,使动画生效
el.offsetHeight
el.style.opacity = 1
// 动画完成时调用 done
done()
}
// 进入过渡后
const onAfterEnter = (el) => {
console.log('进入完成')
}
// 离开过渡前
const onBeforeLeave = (el) => {
el.style.opacity = 1
}
// 离开过渡中
const onLeave = (el, done) => {
el.style.opacity = 0
done()
}
// 离开过渡后
const onAfterLeave = (el) => {
console.log('离开完成')
}
</script>
4. 列表过渡
javascript
<template>
<!--
transition-group 用于列表过渡
tag 指定渲染的元素
-->
<transition-group
name="list"
tag="ul"
>
<li
v-for="item in items"
:key="item.id"
class="list-item"
>
{{ item.text }}
</li>
</transition-group>
</template>
<script setup>
import { ref } from 'vue'
const items = ref([
{ id: 1, text: '项目 1' },
{ id: 2, text: '项目 2' },
{ id: 3, text: '项目 3' }
])
// 添加项目
const addItem = () => {
items.value.push({
id: items.value.length + 1,
text: `项目 ${items.value.length + 1}`
})
}
// 删除项目
const removeItem = (index) => {
items.value.splice(index, 1)
}
</script>
<style>
/* 列表项的基础样式 */
.list-item {
display: inline-block;
margin-right: 10px;
}
/* 进入和离开的过渡 */
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
/* 移动过渡 */
.list-move {
transition: transform 0.5s ease;
}
/* 进入前和离开后的状态 */
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
</style>
5. 状态过渡
javascript
<template>
<div>
<!-- 数字动画 -->
<div class="number">
{{ animatedNumber }}
</div>
<!-- 颜色动画 -->
<div
class="color-block"
:style="{ backgroundColor: color }"
></div>
</div>
</template>
<script setup>
import { ref, reactive, watch } from 'vue'
import gsap from 'gsap'
// 数字动画
const number = ref(0)
const animatedNumber = ref(0)
watch(number, (newValue) => {
gsap.to(animatedNumber, {
duration: 1,
value: newValue
})
})
// 颜色动画
const color = ref('#42b883')
const changeColor = () => {
color.value = color.value === '#42b883' ? '#35495e' : '#42b883'
}
</script>
<style>
.color-block {
width: 100px;
height: 100px;
transition: background-color 1s;
}
</style>
6. 可复用的过渡组件
javascript
<!-- src/components/FadeTransition.vue -->
<template>
<transition
name="custom-fade"
:duration="duration"
v-bind="$attrs"
>
<slot></slot>
</transition>
</template>
<script setup>
defineProps({
duration: {
type: [Number, Object],
default: 300
}
})
</script>
<style>
.custom-fade-enter-active,
.custom-fade-leave-active {
transition: opacity 0.3s ease;
}
.custom-fade-enter-from,
.custom-fade-leave-to {
opacity: 0;
}
</style>
<!-- 使用方式 -->
<template>
<FadeTransition :duration="500">
<div v-if="show">内容</div>
</FadeTransition>
</template>
7. 路由过渡
javascript
<!-- App.vue -->
<template>
<router-view v-slot="{ Component }">
<transition
name="route"
mode="out-in"
>
<component :is="Component" />
</transition>
</router-view>
</template>
<style>
.route-enter-active,
.route-leave-active {
transition: opacity 0.5s ease;
}
.route-enter-from,
.route-leave-to {
opacity: 0;
}
</style>
8. 组合动画示例
javascript
<template>
<div class="container">
<transition
name="modal"
@before-enter="onBeforeEnter"
@enter="onEnter"
@leave="onLeave"
>
<div v-if="show" class="modal">
<div class="modal-content">
<h2>标题</h2>
<p>内容</p>
<button @click="show = false">关闭</button>
</div>
</div>
</transition>
</div>
</template>
<script setup>
import { ref } from 'vue'
import gsap from 'gsap'
const show = ref(false)
// 进入前
const onBeforeEnter = (el) => {
el.style.opacity = 0
const content = el.querySelector('.modal-content')
content.style.transform = 'scale(0.8)'
}
// 进入中
const onEnter = (el, done) => {
// 背景淡入
gsap.to(el, {
duration: 0.3,
opacity: 1
})
// 内容缩放
const content = el.querySelector('.modal-content')
gsap.to(content, {
duration: 0.3,
scale: 1,
onComplete: done
})
}
// 离开
const onLeave = (el, done) => {
// 背景淡出
gsap.to(el, {
duration: 0.3,
opacity: 0
})
// 内容缩放
const content = el.querySelector('.modal-content')
gsap.to(content, {
duration: 0.3,
scale: 0.8,
onComplete: done
})
}
</script>
<style scoped>
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
background: white;
padding: 20px;
border-radius: 8px;
transform-origin: center;
}
</style>
这些示例涵盖了 Vue3 中动画的主要使用场景。记住:
- 使用 transition 组件处理单元素/组件过渡
- 使用 transition-group 处理列表过渡
- 可以使用 JavaScript 钩子实现复杂动画
- 考虑使用第三方动画库增强效果
- 注意性能优化和动画的适用场景