Vue.js - GSAP动画库使用详解(实现过渡动画)
作者:hangge | 2026-04-17 08:44
在某些情况下,我们希望通过 JavaScript 实现一些动画效果,这时可以选择非常流行的 GSAP 动画库。GSAP 是 GreenSock Animation Platform 的缩写,适用于 DOM、SVG、数值、时间轴组合等复杂动画场景。它可以通过 JavaScript 的方式为 CSS 属性、SVG、Canvas 等设置动画。先我将通过样例演示如何安装并使用 GSAP 动画库。
1,安装 GSAP 动画库
在终端中进行项目根目录,执行如下命令安装即可:
npm install gsap
2,CSS 属性动画及 timeline 样例
(1)下面使用 GSAP 实现一个带有淡入、淡出动画的列表切换效果:
- 组件加载时会通过 playIn() 对列表项执行由下向上的逐项(stagger)进入动画。
- 点击“显示/隐藏”按钮时,通过 toggle() 根据 visible 状态决定播放进入或反向播放离场动画。
- playOut() 使用 GSAP 的 reverse() 让时间线倒放,使列表以相反顺序隐去,并在动画结束后销毁 timeline,避免重复叠加。
<template>
<div>
<button @click="toggle">显示/隐藏</button>
<div class="list">
<div v-for="(item, index) in list" :key="item.id" class="list-item" ref="items">
{{ item.text }}
</div>
</div>
</div>
</template>
<script>
import { gsap } from "gsap";
export default {
data() {
return {
visible: true,
list: [
{ id: 1, text: "列表项一" },
{ id: 2, text: "列表项二" },
{ id: 3, text: "列表项三" },
],
tl: null,
};
},
mounted() {
this.playIn();
},
methods: {
// 显示动画
playIn() {
if (this.tl) this.tl.kill();
const nodes = this.$refs.items;
gsap.set(nodes, { opacity: 1, y: 0 });
this.tl = gsap.timeline();
this.tl.from(nodes, {
opacity: 0,
y: 20,
stagger: 0.08,
duration: 0.45,
ease: "power2.out",
});
},
// 隐藏动画
playOut() {
if (!this.tl) return;
// 反向播放并在结束后销毁 timeline
this.tl.timeScale(1.2).reverse().then(() => {
this.tl.kill();
this.tl = null;
});
},
// 切换显示/隐藏
toggle() {
this.visible = !this.visible;
if (this.visible) {
this.playIn();
} else {
this.playOut();
}
},
},
beforeDestroy() {
if (this.tl) this.tl.kill();
},
};
</script>
<style>
.list-item {
margin: 8px 0;
padding: 10px;
background: #f7f7f7;
border-radius: 4px;
}
</style>
(2)运行效果如下,当点击“显示/隐藏”按钮时,列表项会以平滑的动画依次进入或反向退出,实现一个带有交错(stagger)效果的动态展示切换。

3,实现数字变化效果
(1)下面借助 GSAP 动画库实现一个数字变化效果:
- 首先,在 watch 中监听 <input> 的输入,当用户输入数字时,会触发 watch 中定义的 counter 函数。
- 接着,该函数使用 gsap 的 to 函数为 Vue 实例的 showNumber 属性应用动画。即在 1 秒内,showNumber 的值将由 1 过渡到 <input> 输入的数值。这样就可以看到 showNumber 数字递增的效果。
<template>
<div class="app">
<input type="number" v-model="counter" style="margin-bottom:10px">
<h2>当前计数: {{ showNumber.toFixed(0) }}</h2>
</div>
</template>
<script>
import gsap from 'gsap';
export default {
data() {
return {
counter: 1,
showNumber: 0
}
},
watch: {
counter(newValue) {
// 参数一:目标对象(这里是Vue实例)
// 参数二:给目标对象中showNumber属性添加动画(在1s中showNumber由1过度到input输入的数值)
gsap.to(this, { duration: 1, showNumber: newValue })
}
}
}
</script>
(2)运行效果如下,当我们在输入框中输入“9999”时,当前计数将会从 1 递增到 9999。

4,配合 <transition> 组件实现过渡动画
(1)下面样例通过 <transition> 组件的事件和 JavaScript 钩子,配合 GSAP 动画库实现元素的显示或隐藏动画:
- 在 <transition> 组件中监听了 enter 和 leave 事件。在元素被插入 DOM 之后的下一帧,会调用 enter 方法,该方法接收两个参数:el 和 done。其中,el 是需要做动画的 DOM 对象(<h4> 元素),done 表示过渡结束的回调函数。
- 在 <transition> 组件设置:css="false" 后,表示 JavaScript 全权负责控制动画的过渡。在这种情况下,对 @enter 和 @leave 钩子来说,调用回调函数 done 就是必需的。
- 接着,在 enter 方法中使用 gsap 的 from 函数为 <h4> 元素应用动画,即 <h4> 元素从右边 200 处由小到大移动到默认位置。在 gsap 中动画执行完成之后会回调 onComplete 函数,这里通过直接将 done 函数传递给 onComplete 来完成这次动画。
- 同样,当离开过渡开始时会调用 leave 方法。我们在该方法中使用 gsap 的 to 函数为 <h4> 元素应用动画,即 <h4> 元素从默认位置向右移动 200 并缩小为 0。
<template>
<div class="app">
<button @click="isShow = !isShow">显示/隐藏</button>
<transition @enter="enter" @leave="leave" :css="false">
<h4 v-if="isShow">Hello World</h4>
</transition>
</div>
</template>
<script>
import gsap from 'gsap';
export default {
data() {
return {
isShow: true,
}
},
methods: {
// 进入动画
enter(el, done) {
console.log("enter", el);
// h4元素在整个进入过渡的阶段中应用了下面动画
gsap.from(el, {
scale: 0,
x: 200,
onComplete: done
})
},
// 离开动画
leave(el, done) {
console.log("leave", el);
// h4元素在整个离开过渡的阶段中应用了下面动画
gsap.to(el, {
scale: 0,
x: 200,
onComplete: done
})
}
}
}
</script>
<style scoped>
h4 {
border: 1px solid #ddd;
width: 120px;
margin-top: 20px;
padding: 5px;
text-align: center;
}
</style>
(2)运行效果如下,当单击“显示/隐藏”按钮时,<h4> 元素将从默认位置缓慢向右移动 200,并逐渐缩小为 0。 当再次单击“显示/隐藏”按钮时,<h4> 元素将从右侧 200 处缓慢移动到默认位置,并逐渐放大。

5,配合 <transition-group> 组件实现过渡动画
(1)下面是一个通过输入框筛选列表项条目的样例,我们利用 GSAP 库的延迟(delay)属性实现筛选时,列表条目交替消失的动画效果。
- 首先在 <transition-group> 组件中添加:css="false" 属性,以禁用 <style> 标签中的 CSS 动画。
- 接着,监听 before-enter、enter 和 leave 事件。
- 在 beforeEnter 方法中初始化 <li> 元素,即 <li> 元素插入 <ul> 前是全透明的,并且高度为 0。
- 在 enter 方法中指定所有添加的 <li> 元素是从全透明且高度为 0 过渡到不透明且高度为 1em 的动画,为每个 <li> 元素指定依次递增的延时以实现交替效果;
- 在 leave 方法中指定所有需移除的 <li> 元素是从不透明且高度为 1.5em 过渡到全透明且高度为 0 的动画,为 <li> 元素指定依次递增的延时以实现交替效果。
- 最后,在动画执行完成时都需要回调 done 函数,结束动画。
<template>
<div>
<input v-model="keyword">
<transition-group tag="ul" :css="false"
@before-enter="beforeEnter" @enter="enter" @leave="leave">
<!-- 每个li绑定了data-index属性,该值用来计算当前li动画的delay延时 -->
<li v-for="(item, index) in showNames" :key="item" :data-index="index">
{{ item }}
</li>
</transition-group>
</div>
</template>
<script>
import gsap from 'gsap';
export default {
data() {
return {
names: ["abc", "cba", "nba", "hangge", "lilei", "hmm", "kobe", "james"],
keyword: ""
}
},
computed: {
showNames() {
return this.names.filter(item => item.indexOf(this.keyword) !== -1)
}
},
methods: {
// 进入前
beforeEnter(el) {
console.log('beforeEnter=>', el)
el.style.opacity = 0;
el.style.height = 0;
},
// 进入动画
enter(el, done) {
console.log('enter=>', el)
gsap.to(el, {
opacity: 1,
height: "1.5em",
// el.dataset.index 是拿到li元素上data-index绑定的属性的值
delay: el.dataset.index * 0.1,
onComplete: done
})
},
// 离开动画
leave(el, done) {
console.log('leave=>', el)
gsap.to(el, {
opacity: 0,
height: 0,
delay: el.dataset.index * 0.1,
onComplete: done
})
}
}
}
</script>
(2)运行效果如下,当我们在输入框中输入或删除关键字时,在列表中移除或添加 <li> 元素都会有交替动画。

全部评论(0)