Gsap 动画库使用笔记
安装 Gsap
创建动画
例如,如果 html 元素创建动画,将 ‘.box’ 类的元素设置 1 秒时间水平移动 200px 的动画。可以这么编写:
1 2 3
| import gsap from 'gsap'
gsap.to('.box', { x: 200 })
|
在 three.js 中如果我们想要将物体,例如立方体移动设置 1 秒时间水平移动 200px 的动画。可以这么编写
1 2
| import gsap from 'gsap' gsap.to(cube.position, { x: 200 })
|
gsap.to() - 这是最常见的补间类型。是设置当前元素或者变量的状态,到设置的状态的补间动画。所谓的补间动画,就是 2 个关键帧(即 2 种物体的状态)有了,框架自带计算出中间某个时刻的状态,从而填补 2 个状态间,动画的空白时刻,从而实现完整动画。
gsap.to 有 2 个参数,第一个是目标元素或者变量。如果传入的是.box 之类的 css 字符串选择器,GSAP 在后台使用 document.querySelectorAll()选中页面的匹配的元素。当第一个目标是对象时,GSAP 就会对其属性值进行修改来实现补间动画。
GSAP 设置动画的属性
下面演示向右水平移动+旋转.box 元素的效果
1 2 3 4 5
| gsap.to('.box', { duration: 2, x: 200, rotation: 360, })
|
默认情况下,GSAP 将使用 px 和度数进行变换,但您可以使用其他单位,例如 vw、弧度,甚至可以进行自己的 JS 计算或相对值!
1 2 3 4 5 6
| x : 200 , x : "+=200" x : '40vw' , x : () => window 。innerWidth / 2 , rotation:360 rotation:“1.25rad”
|
如果第一个参数目标不是 html 元素,也可以是对象。。您可以针对任何对象的任何属性,甚至是您创建的任意属性,如下所示
1 2 3 4 5 6
| let obj = { myNum: 10, myColor: 'red' } gsap.to(obj, { myNum: 200, myColor: 'blue', onUpdate: () => console.log(obj.myNum, obj.myColor), })
|
这里可以让 obj.myNum 值从 10 变化到 200,也可以让颜色 myColor 的值从红色变化到蓝色。每一次更新值的时候,执行 onUpdate 所设置的回调函数。
GSAP 特殊属性控制动画
duration:动画持续时间(秒) 默认值:0.5
delay:动画开始前的延迟量(秒)
repeat:动画应该重复多少次。-1 为一直重复
yoyo:如果为 true,则每隔一个重复,补间将沿相反方向运行。(像悠悠球一样)默认值:false
ease:控制动画期间的变化率。
onComplete:动画完成时调用的函数
onUpdate:动画值更新时调用的函数
ease 动画属性设置
缓动可能是动作设计中最重要的部分。精心挑选的轻松将为您的动画增添个性并注入活力。
在下面的演示中看看 no ease 和 bounce ease 之间的区别!绿色盒子以匀速的速度旋转,而紫色盒子带有“反弹”旋转动画,感觉就不一样。
1 2 3
| gsap.to('.green', { rotation: 360, duration: 2, ease: 'none' })
gsap.to('.purple', { rotation: 360, duration: 2, ease: 'bounce.out' })
|
在引擎内部,“ease”是一种数学计算,用于控制补间期间的变化率。但不用担心,框架会为您做所有的数学计算!您只需坐下来选择最适合我们的动画的效果即可。
对于大多数效果,分为三种类型 in、out、inOut。这些控制了轻松过程中的动量。
像这样的 设置 ease:”power1.out” 是 UI 过渡的最佳选择;它们启动速度很快,这有助于 UI 感觉反应灵敏,然后它们在接近尾声时放松,给人一种自然的摩擦感。
理解 ease 的最好方法是玩转 ease 配置的可视化工具!
地址:https://greensock.com/get-started/#greenSockEaseVisualizer
Staggers 交错
这是我们最喜欢的技巧之一!如果补间有多个目标,您可以轻松地在每个动画的开始之间添加一些交错效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| gsap.from('.box', { duration: 2, scale: 0.5, opacity: 0, delay: 0.5, stagger: 0.2, ease: 'elastic', force3D: true, })
document.querySelectorAll('.box').forEach(function (box) { box.addEventListener('click', function () { gsap.to('.box', { duration: 0.5, opacity: 0, y: -100, stagger: 0.1, ease: 'back.in', }) }) })
|
这里 stagger 设置 0.2,即为将.box 选中多个元素设置为每隔 0.2 秒开始运动 1 个元素实现效果。 作者:老陈打码 https://www.bilibili.com/read/cv17889719 出处:bilibili
时间线-Timelines
时间线是创建易于调整、有弹性的动画序列的关键。当您将补间添加到时间线时,默认情况下,它们会按照添加的顺序一个接一个地播放。
1 2 3 4 5 6 7
| let tl = gsap.timeline()
tl.to('.green', { x: 600, duration: 2 }) tl.to('.purple', { x: 600, duration: 1 }) tl.to('.orange', { x: 600, duration: 1 })
|
Threejs 场景种应用
设置立方体旋转
1 2 3 4 5
| gsap.to(cube.rotation, { x: 2 * Math.PI, duration: 5, ease: 'power1.inOut', })
|
设置立方体来回往返运动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| var animate1 = gsap.to(cube.position, { x: 5, duration: 5, ease: 'power1.inOut', repeat: -1, yoyo: true, delay: 2, onComplete: () => { console.log('动画完成') }, onStart: () => { console.log('动画开始') }, })
|
让双击画面,控制立方体动画暂停和恢复动画,前面创建的 animate1 这个动画实例,有 isActive 方法,可以用来获取当前动画是暂停还是播放状态,播放状态时 isActive 方法返回为 true,暂停时为 false,根据这个状态来调用 pause 方法来暂停动画和恢复动画。
1 2 3 4 5 6 7 8 9 10
| window.addEventListener('dblclick', () => { if (animate1.isActive()) { animate1.pause() } else { animate1.resume() } })
|
综合上述代码
在前面创建的项目中的 main.js 文件写入代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import gsap from 'gsap'
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 )
camera.position.set(0, 0, 10) scene.add(camera)
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1) const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 })
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
cube.rotation.set(Math.PI / 4, 0, 0, 'XZY')
scene.add(cube)
console.log(cube)
const renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
const controls = new OrbitControls(camera, renderer.domElement)
const axesHelper = new THREE.AxesHelper(5) scene.add(axesHelper)
const clock = new THREE.Clock()
var animate1 = gsap.to(cube.position, { x: 5, duration: 5, ease: 'power1.inOut', repeat: -1, yoyo: true, delay: 2, onComplete: () => { console.log('动画完成') }, onStart: () => { console.log('动画开始') }, }) gsap.to(cube.rotation, { x: 2 * Math.PI, duration: 5, ease: 'power1.inOut' })
window.addEventListener('dblclick', () => { if (animate1.isActive()) { animate1.pause() } else { animate1.resume() } })
function render() { renderer.render(scene, camera) requestAnimationFrame(render) }
render()
|