文章目录
- Vue3 过渡动画效果
- 概述
- `<Transition>`组件
- 简单使用
- 为过渡效果命名
- 自定义过渡class
- JavaScript动画效果
- 元素间过渡
- `<transition-group>`组件
- 列表动画
- 状态动画
Vue3 过渡动画效果
概述
Vue 提供了两个内置组件,可以帮助你制作基于状态变化的过渡和动画:
<Transition>
会在一个元素或组件进入和离开 DOM 时应用动画。<TransitionGroup>
会在一个v-for
列表中的元素或组件被插入,移动,或移除时应用动画。
<Transition>
组件
<Transition>
是一个内置组件,它可以将进入和离开应用到通过默认插槽传递给它的元素或组件上。
进入或离开可以由以下的条件之一触发:
- 由
v-if
所触发的切换 - 由
v-show
所触发的切换
简单使用
v-enter-from
:进入动画的起始状态。v-enter-active
:进入动画的生效状态。这个 class 可以被用来定义进入动画的持续时间、延迟与速度曲线类型。v-enter-to
:进入动画的结束状态。v-leave-from
:离开动画的起始状态。v-leave-active
:离开动画的生效状态。这个 class 可以被用来定义离开动画的持续时间、延迟与速度曲线类型。v-leave-to
:离开动画的结束状态。
<script>
export default {
data() {
return {
show: false,
}
},
methods: {
handleClick() {
this.show = !this.show;
}
}
}
</script>
<template>
<div>
<transition>
<div v-if="show">hello world</div>
</transition>
<button @click="handleClick">切换</button>
</div>
</template>
<style>
/* 入场效果 */
.v-enter-from {
opacity: 0;
}
/* 定义过渡效果 */
.v-enter-active {
transition: opacity 3s ease-out;
}
.v-enter-to {
opacity: 1;
}
/* 出场效果 */
.v-leave-from {
opacity: 1;
}
.v-leave-active {
transition: opacity 3s ease-in;
}
.v-leave-to {
opacity: 0;
}
</style>
为过渡效果命名
可以给 <Transition>
组件传一个 name
prop 来声明一个过渡效果名:
<script>
export default {
data() {
return {
show: false,
}
},
methods: {
handleClick() {
this.show = !this.show;
}
}
}
</script>
<template>
<div>
<transition name="abc">
<div v-if="show">hello world222</div>
</transition>
<button @click="handleClick">切换</button>
</div>
</template>
<style>
@keyframes my-anim {
0% {
transform: translateX(50px);
}
50% {
transform: translateX(-50px);
}
100% {
transform: translateX(50px);
}
}
.abc-enter-active {
animation: my-anim 3s;
}
.abc-leave-active {
animation: my-anim 3s ease-out;
}
</style>
自定义过渡class
可以向 <Transition>
传递以下的 props 来指定自定义的过渡 class:
enter-from-class
enter-active-class
enter-to-class
leave-from-class
leave-active-class
leave-to-class
<script>
export default {
data() {
return {
show: false,
}
},
methods: {
handleClick() {
this.show = !this.show;
}
}
}
</script>
<template>
<div>
<transition enter-active-class="myenter" leave-active-class="myleave">
<div v-if="show">hello world333</div>
</transition>
<button @click="handleClick">切换</button>
</div>
</template>
<style>
@keyframes my-anim {
0% {
transform: translateX(50px);
}
50% {
transform: translateX(-50px);
}
100% {
transform: translateX(50px);
}
}
.myenter {
animation: my-anim 3s;
}
.myleave {
animation: my-anim 3s;
}
</style>
JavaScript动画效果
可以通过监听 <Transition>
组件事件的方式在过渡过程中挂上钩子函数。
添加一个 :css="false"
prop。这显式地向 Vue 表明可以跳过对 CSS 过渡的自动探测。
对于 @enter
和 @leave
钩子来说,回调函数 done
就是必须的。否则,钩子将被同步调用,过渡将立即完成。
<script>
export default {
data() {
return {
show: false,
}
},
methods: {
handleClick() {
this.show = !this.show;
},
handleBeforeEnter(el) {
el.style.color = "red";
},
handleEnter(el, done) {
let animation = setInterval(() => {
let color = el.style.color;
if (color === "red") {
el.style.color = "green";
} else {
el.style.color = "red";
}
}, 1000)
setTimeout(() => {
clearInterval(animation);
done(); //通知动画结束
}, 3000)
},
handleAfterEnter(el) {
alert("结束")
},
}
}
</script>
<template>
<div>
<transition :css="false" @before-enter="handleBeforeEnter" @enter="handleEnter" @after-enter="handleAfterEnter">
<div v-if="show">hello world444</div>
</transition>
<button @click="handleClick">切换</button>
</div>
</template>
元素间过渡
除了通过 v-if
/ v-show
切换一个元素,我们也可以通过 v-if
/ v-else
/ v-else-if
在几个组件间进行切换,只要确保任一时刻只会有一个元素被渲染即可。
如果你想在某个节点初次渲染时应用一个过渡效果,你可以添加 appear
prop:
<script>
export default {
data() {
return {
show: false,
}
},
methods: {
handleClick() {
this.show = !this.show;
}
}
}
</script>
<template>
<div>
<transition mode="out-in" appear>
<div v-if="show">hello</div>
<div v-else="show">world</div>
</transition>
<button @click="handleClick">切换</button>
</div>
</template>
<style>
.v-enter-to,
.v-leave-from {
opacity: 1;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.v-enter-active,
.v-leave-active {
transition: opacity 1s ease-in;
}
</style>
<transition-group>
组件
<transition-group>
是一个内置组件,用于对 v-for
列表中的元素或组件的插入、移除和顺序改变添加动画效果。
列表动画
<script>
export default {
data() {
return {
list: [1, 2, 3]
}
},
methods: {
handleClick() {
this.list.unshift(this.list.length + 1);
}
}
}
</script>
<template>
<div>
<transition-group>
<span class="list-item" v-for="item in list" :key="item">{{ item }}</span>
</transition-group>
<button @click="handleClick">添加</button>
</div>
</template>
<style>
.list-item {
display: inline-block;
margin-right: 10px;
}
.v-enter-from {
opacity: 0;
transform: translateY(30px);
}
.v-enter-to {
opacity: 1;
transform: translateY(0);
}
.v-enter-active {
transition: all 0.5s ease-in;
}
.v-move {
transition: all 0.5s ease-in;
}
</style>
状态动画
<script>
export default {
data() {
return {
animNum: 1
}
},
methods: {
handleClick() {
if (this.animNum < 10) {
let interval = setInterval(() => {
this.animNum++;
if (this.animNum === 10) {
clearInterval(interval);
}
}, 100);
}
}
}
}
</script>
<template>
<div>
<transition-group>
<div>{{ animNum }}</div>
</transition-group>
<button @click="handleClick">添加</button>
</div>
</template>