前言
本文主要介绍gsap基本使用以及如何在react中使用gsap跨组件控制。
废话
队长昨天凌晨跟我说,他接了一个单子,是做五天内交付一个3D炫酷页面的,考虑团队本身就有一个项目还没完成和队里就我一个前端切图仔,问我的意愿。
密码的,我当然不接啊,当🐮🐴也不能累死。但当知道队长跟我说他出$200的时候,做,必须做!(没办法,他给太多了)
我的想法是结合threejs打造一个3D页面,但是光3D效果就让人头痛了,更别说搞动画了,那么有什么办法能方便我创建动画效果呢?
在光顾了许多外国网站,发现许多网站都用到了它——gsap!
不用不知道,用了才知道这玩意有多香,极大提高了我的开发效率
参考文献
docsHome | GSAP | Docs & Learning
GSAP 中文教程 中文文档 |官方文档 官方教程翻译 |好奇代码出品
什么是GSAP ?
在官方文档中说到,它可以为任何内容制作动画!amazing!我就用它和threejs结合的很好。
安装:
npm install gsap
tween的基本使用
gsap.to
gsap.to(".box", { x: 200 })
像这样的一个动画叫做'Tween', 这句话的意思的是告诉tween,让一个叫类名box的家伙移动到x是200的位置
我们来实战一下
import gsap from "gsap"
gsap.to('.box', { x: 100, repeat: 1000 })
function App() {
return (
<>
<body className="flex justify-center items-center min-h-screen">
<div className="box bg-green-500 w-10 h-10 justify-center items-center text-white">
我正在移动
</div>
</body>
</>
)
}
export default App
我们来看下这段语法
我们可以看到这句代码里面,这里有一个方法(method),一个目标(target),还有一个对象数据(variables)。
动画方法们(Methods)
有四种Tween的动画方式
— gsap.to()这是一种最常用的tween动画,就是让元素从初始状态变化到目标状态。
— gsap.from()有点像to方法的逆向变化,就是让元素从目标状态变化到初始状态。
— gsap.fromTo()需要自己定义两个状态的数据,然后从前一个变化到后一个。
— gsap.set()直接设置成想要的状态,没有任何过度与动画效果。本质上就是duration为0的 .to 方法
gsap.from
import gsap from "gsap"
gsap.from('.box', { x: -100, repeat: 1000 })
function App() {
return (
<>
<body className="flex justify-center items-center min-h-screen">
<div className="box bg-green-500 w-10 h-10 justify-center items-center text-white">
我正在移动
</div>
</body>
</>
)
}
export default App
gsap.fromTo
import gsap from "gsap"
gsap.fromTo('.box', { x: 100, repeat: 1000 },{y:100,repeat:1000})
function App() {
return (
<>
<body className="flex justify-center items-center min-h-screen">
<div className="box bg-green-500 w-10 h-10 justify-center items-center text-white">
我正在移动
</div>
</body>
</>
)
}
export default App
gsap.set
import gsap from "gsap"
gsap.set('.box', { x: 100})
function App() {
return (
<>
<body className="flex justify-center items-center min-h-screen">
<div className="box bg-green-500 w-10 h-10 justify-center items-center text-white">
我正在移动
</div>
</body>
</>
)
}
export default App
因为是一瞬间的不太好演示,大家自行尝试即可。
目标元素target
接下来我们需要去告诉GSAP去让什么元素变化。GSAP在底层实际上是使用了document.querySelector( )去选择元素,所以你可以用任何css选择器进行元素的选择。或者你也可以直接传入一个DOM元素或者一个数组
import gsap from "gsap"
let box = document.querySelector(".box")
gsap.to(box,{x:200,repeat:1000})
function App() {
return (
<>
<body className="flex justify-center items-center min-h-screen">
<div className="box bg-green-500 w-10 h-10 justify-center items-center text-white">
我正在移动
</div>
</body>
</>
)
}
export default App
变化数据对象(variables)
这个对象包含着所有动画变化相关的信息。你可以设置任意的你想要发生变化的属性和值,或者一些特殊的会影响动画过程的一些属性,比如duration(动画时长),onComplete(动画完成时触发事件)或者repeat(动画重复的次数。
关于variables这里不展开介绍,因为它太多太多了,后期我会出一篇常用的variables的文章。
- 注意在gsap中基本上什么都能变,CSS属性、自定义的对象属性,甚至CSS变量和复杂的字符串。
- 这里更加推荐使用transfrom相关的属性来实现动画效果,而不是那些会影响到布局的属性,比如 left top margin,这样不仅不会导致页面出现回流重绘进而影响性能,而且也能使动画效果更好
常见的tansform如下
Timelines 时间线
欢迎回到GSAP的入门指南。如果你没有读过前面一篇文章,你可以先去阅读一下。
接下来,让我们接着来聊是时间线功能吧。
时间线能让我们创建非常容易调节的、很灵活的顺序动画效果。下面就是一个简单的包含着三个tween动画的timeline实例效果。 默认情况下,在同一时间线下 这些动画是依次添加的,他们在变化的时候也是依次执行,而且是一个执行完之后再下一个执行。
// 创建一个Timeline类型的实例
let tl = gsap.timeline()
// 把tween动画添加到timeline实例上,注意我们在用的是tl.to 而不是gsap.to
tl.to(".box1", { x: 600, duration: 2 });
tl.to(".box2", { x: 600, duration: 1 });
tl.to(".box3", { x: 600, duration: 1 });
但是,如果我们想要在动画之间加一个停顿或者说间隔改怎么办呢
let tl = gsap.timeline()
tl.to(".box1", { x: 600, duration: 2 });
tl.to(".box2", { x: 600, duration: 1, delay: 1 });
tl.to(".box3", { x: 600, duration: 1 });
有一个方式就是我们可以给某个tween动画在启动前提添加一个delay。但是这样的话,一点都不灵活。又或者,如果我们想要实现动画之间在时间上重叠,又或者几个动画同时启动,这些该怎么实现呢?
位置参数 Position Parameter
这个参数能帮我们方便的实现执行顺序和执行时间点的精确控制,我们来看下这个demo。
import gsap from "gsap"
let tl = gsap.timeline()
// box1 会在时间线开始0.5后移动100px
tl.to(".box1", {y: 100, duration: 1 },0.5)
// box2 会之前一个添加的动画同时开始运动
tl.to(".box2", {y: 100, duration: 1},"<")
// box3 之前所有动画都结束一秒后再开始运动
tl.to(".box3", {y: 100, duration: 1},"+=0.5")
function App() {
return (
<>
<body className="flex justify-center items-center min-h-screen">
<div className="box1 bg-green-500 w-10 h-10 justify-center items-center text-white">
我是box1
</div>
<div className="box2 bg-red-500 w-10 h-10 justify-center items-center text-white">
我是box2
</div>
<div className="box3 bg-blue-500 w-10 h-10 justify-center items-center text-white">
我是box3
</div>
</body>
</>
)
}
export default App
这里不知道为什么把运行效果弄上来以后,掘金就保存不了,大家自行尝试即可,实际效果是0.5秒后,box1和box2一起移动,最后box3动
我们还可以使用各种写法——绝对的秒数,百分比,相对值等等方式来决定tween动画在什么时候开始。
特殊属性 Special Properties
Timelines可以设置的动画属性和tween动画绝大部分是一样的,比如像repeat和delay,可以让你轻松的设定整个顺序动画的动画属性。
import gsap from "gsap"
let tl = gsap.timeline({repeat:100})
// box1 会在时间线开始0.5后移动100px
tl.to(".box1", {y: 100, duration: 1 })
function App() {
return (
<>
<body className="flex justify-center items-center min-h-screen">
<div className="box1 bg-green-500 w-10 h-10 justify-center items-center text-white">
我是box1
</div>
</body>
</>
)
}
export default App
时间线的默认设置 Timeline Defaults
如果你发现自己总是一遍又一遍的写同一个属性,那么你可以使用 defaults来进行设置。
任何添加到时间线上的defaults的属性,都会被添加到这个时间线上的tween动画继承,像是通过to(),from()和fromTo()方式添加到时间线上的动画效果都是有这个继承效果的。利用这个方式可以让你的代码更简洁一些。
import gsap from "gsap"
let tl = gsap.timeline({
defaults:1
})
// box1 会在时间线开始0.5后移动100px
tl.to(".box1", {y: 100})
.to(".box2",{y:200})
.to(".box3",{y:300})
function App() {
return (
<>
<body className="flex justify-center items-center min-h-screen">
<div className="box1 bg-green-500 w-10 h-10 justify-center items-center text-white">
我是box1
</div>
<div className="box2 bg-red-500 w-10 h-10 justify-center items-center text-white">
我是box2
</div>
<div className="box3 bg-blue-500 w-10 h-10 justify-center items-center text-white">
我是box3
</div>
</body>
</>
)
}
export default App
控制动画 Controlling your animations
我们之前讲的动画效果都是页面加载后就启动或者延迟一定时间启动。但是如果我们想要对动画有更多一点的控制能力的话该怎么做呢?
比较常见的就是比如说我们想要点击某个按钮或有了某个交互行为之后才会让元素进行动画效果。
那么控制动画的几个方法呢可以帮我们实现这个需求,在tween和timeline上都有这些方法,play,pause,reverse或者是加速变化。
// 通过一个变量保存对Tween或者Timeline实例的引用
let tween = gsap.to(".box", {duration: 1, x: 100});
// 暂停
tween.pause();
// 恢复(继续)
tween.resume();
// 反向变化
tween.reverse();
// 直接切换到整个动画变化时长的0.5秒的时间点的状态
tween.seek(0.5);
// 直接切换到整个变化过程的1/4的节点的状态
tween.progress(0.25);
// 让运动减速到0.5倍
tween.timeScale(0.5);
// 让变化加速到原来的2倍
tween.timeScale(2);
// 直接销毁tween实例,让垃圾回收机制可以处理该实例所占用的内存
tween.kill();
动画事件 Callbacks
如果你需要知道动画是什么启动的,或者是在动画的某个时机执行一些代码,那么你可以使用动画事件。所有的Tween和timelines都有这些事件。
-
onComplete:动画结束时触发
-
onStart:动画开始时触发
-
onUpdate:只要动画运行,每一帧都会触发(元素有属性变化时)
-
onRepeat:每次动画重复时触发
-
onReverseComplete:当动画反向执行后运动到变化起始点时触发
import gsap from "gsap"
let tl = gsap.timeline({
defaults:{
duration:3
},
repeat:2,
onComplete: () => console.log("the tween is complete")
})
// box1 会在时间线开始0.5后移动100px
tl.to(".box1", {y: 100})
function App() {
return (
<>
<body className="flex justify-center items-center min-h-screen">
<div className="box1 bg-green-500 w-10 h-10 justify-center items-center text-white">
我是box1
</div>
</body>
</>
)
}
export default App
插件 Plugins
上面都是基本用法,但是插件,它能让你化身浩克!!!
这里介绍使用方法以及简单给大家展示一个。
import gsap from "gsap"
import { Draggable } from "gsap/Draggable";
//注册插件
gsap.registerPlugin(Draggable)
//使用插件
Draggable.create(".box1");
function App() {
return (
<>
<body className="flex justify-center items-center min-h-screen">
<div className="box1 bg-green-500 w-10 h-10 justify-center items-center text-white">
我是box1
</div>
</body>
</>
)
}
export default App
Draggable提供一种非常简单的方法,使几乎任何 DOM 元素都可以使用鼠标和/或触摸事件进行拖动、旋转、投掷,甚至轻拂滚动的方法。
在React使用useGSAP()跨组件控制动画
在我们开发过程中,常常需要一个组件去控制另一个组件的变化,那么GSAP有没有相关功能呢?
作者查了许多文章,都没有发现,最后在我阅读官方文档的时候找到了——useGSAP。
其实还有其他的方法,但是useGSAP是我认为最简单,最无脑的方式,这里也只介绍它,足以满足开发需求了。
其他的方法后期找时间写。
安装
npm install @gasp/react
import gsap from "gsap"
import { useGSAP } from '@gsap/react';
import Box2 from "./box2";
function App() {
useGSAP(()=>{
let tl = gsap.timeline()
tl.to('.box', {x: 100, duration: 1})
tl.to('.box2',{
y:100,
duration: 1,
})
})
return (
<>
<body className="flex justify-center items-center min-h-screen">
<div className="box bg-green-500 w-10 h-10 justify-center items-center text-white">
我是box1
</div>
<Box2></Box2>
</body>
</>
)
}
export default App
const box2 = () => {
return (
<div className='box2 bg-pink-500 text-white'>
我是box2
</div>
)
}
export default box2
我们使用useGSAP通过类名直接锁定你想要的改变的对象,效果如下
可以发现,我们在box1的中能去操作box2。
关于useGSAP是什么,这里不做说明,官方文档说的比我更清楚 React & GSAP | GSAP | Docs & Learning
注意:在实际开发中如果你使用react,我推荐你使用useGSAP来进行开发。