【译】Tween.js使用指南

8,061 阅读7分钟

系统学习一下Tween.js的使用,对Tween.js官方使用文档进行了翻译,有很多操作细节还有使用方法,收获很多啊!

学习链接

简介

Tween的概念:

  • 以一种平滑的方式改变对象的值,
  • 我们只需要设置需要改变的参数,目标值,运行时间,Tween引擎就会自动帮我们搞定它了。

举一个例子!我们有一个对象position,里面有x 和 y属性

var position = {x: 100, y: 0}

// Create a tween for position first
// 创建一个tween对象,初始值为positionvar tween = new TWEEN.Tween(position)

// Then tell the tween we want to animate the x property over 1000 milliseconds
// 设置position里面的x ,设置时间为1s
tween.to({x: 200}, 1000)

这样就设置好了,但是还不起作用,需要手动启动它,调用start函数

// And set it to start
// 调用tween对象的 start方法
tween.start()

最后一步,启动start方法后,还需要在循环中调用update函数

animate()

function animate() {
	requestAnimationFrame(animate)

	TWEEN.update()    //<----------

}

这样,我们就设置完全部的内容了,它会在一秒的时间内,从x 为100 移动到200

如果想要查看 x 值的改变情况,可以在onUpdate回调函数中打印出来

  • onUpdate方法会在 tween 执行的周期内运行!
tween.onUpdate(function (object) {
	console.log(object.x)
})

在Threejs中使用

  • 移动cube的位置,假如初始位置为 {x: 0, y: 0, z: 0},移动到{x: 100, y: 100, z: 100}
  • 使用时间 10s
var tween = new TWEEN.Tween(cube.position).to({x: 100, y: 100, z: 100}, 10000).start()

animate()

function animate() {
	requestAnimationFrame(animate)
	TWEEN.update()

	threeRenderer.render(scene, camera)
}

这里用了链式调用!

// 01
var tween = new TWEEN.Tween(position).to({x: 200}, 1000).start() 

// 02
var tween = new TWEEN.Tween(position) 
tween.to({x: 200}, 1000)
tween.start()

tween.js 执行动画

Tween.js自身并不能自动运行,需要在周期函数中运行,推荐的函数就是requestAnimationFrame,在周期函数中调用TWEEN.update()

animate()

function animate() {
	requestAnimationFrame(animate)
	// [...]
	TWEEN.update()   //<----------
	// [...]
}

控制 tween 对象

start和stop

start方法,tween执行动画的起点,与之相对应的是stop方法,停止动画

tween.stop();

注!停止一个没有启动的 tween 和已经停止的 tween 是没有效果的,但是也不报错!

update

每一个tween对象,都有update方法,用在周期函数中

  • 我们创建的tween,如果没有分组,都是在默认的组里的,直接使用TWEEN.update()做更新即可
  • 如果使用Tween.Group()进行分组,需要对该组进行update操作!,(下文介绍分组)

image.png

chain

链接:可以在一个tweeen对象执行结束后,继续执行另一个tween对象

// tweenA执行完,执行tweenB
tweenA.chain(tweenB)

// 无限循环
tweenA.chain(tweenB)
tweenB.chain(tweenA)

// 链接多个tween对象!执行多个动画!
tweenA.chain(tweenB, tweenC)

注!WARNING: Calling tweenA.chain(tweenB) actually modifies tweenA so that tweenB is always started when tweenA finishes. The return value of chain is just tweenA, not a new tween.

上文的意思是,我们通过chain的方法链接tweenB,实际上是修改tweenA的内容,这样tweenB就会在tweenA执行完后执行,如果返回当前chain的值,得到的还是tweenA

repeat

重复:如果相要一个tween动画,一直执行下去,可以chain自身,不过更好的方法是,使用repeat方法,通过repeat方法,可以设置重复的次数

  • 比如说,从(0,0,0)位置,移动到(1,1,1)位置
  • 每次都从(0,0,0)位置出发,重复执行
// 重复10次
tween.repeat(10) // repeats 10 times after the first tween and stops

// 重复无限次
tween.repeat(Infinity) // repeats forever

yoyo

这个方法,只在使用了repeat方法后,才能起作用,可以从移动的终点,返回到起点,就像悠悠球一样!

delay

延迟:更复杂的动画,可能就需要延迟设置了,可以在启用start方法后,执行动画

// 1s后执行动画,
tween.delay(1000)
tween.start()

repeatDelay

可以让延迟操作,重复执行

  • 第一动画执行时间,在1s
  • 第二个动画执行时间,在第一个执行完,0.5s
  • 第三个动画执行时间,在第二个执行完,0.5s
tween.delay(1000) // 首次
tween.repeatDelay(500) // 首次之后的。
tween.start()

dynamic

动态:默认为false,主要结合的是 tween.to()方法。

  • to设置的是终点的位置,默认是false,就是动画开始,起点和终点都确定好了。
  • 设置为true,就可以动态的修改终点的位置了!
  • Tween.js / dynamic to… - 案例地址

03.gif

控制 tween 对象 - All

这里介绍的是,tween对象的全局方法,并不是都需要使用,最常用的还是update方法

TWEEN.update(time)

  • 用于更新tween对象(默认分组内的!

TWEEN.getAll & TWEEN.removeAll

Used to get a reference to the active tweens array and to remove all of them from the array with just one call, respectively.

  • TWEEN.getAll用于获取一组 tween对象
  • TWEEN.removeAll用于移除一组 tween对象

TWEEN.add(tween) & TWEEN.remove(tween)

Used to add a tween to the list of active tweens, or to remove a specific one from the list, respectively.

These methods are usually used internally only, but are exposed just in case you want to do something funny.

  • TWEEN.add用于添加 tween对象,到分组中
  • TWEEN.remove用于从分组中移除 tween对象

以上方法,多用于tween.js内部。

tween 分组

我们创建的tween对象,都在默认的分组中,更新动画只需要在周期函数中使用 TWEEN.update()

为什么需要分组?

  • 如果项目很大,有很多的tween对象,它们都处于默认的分组中
  • 执行TWEEN.update() or TWEEN.removeAll()会把所有的都更新 或移除了
  • 进行分组的话,就可以有效的控制哪些需要更新,哪些需要移除了

image.png

设置缓动动画!

把时间分段,在不同的分段中,移动不同的速度!

// 描述一下运行流程。。
// 开始的时候慢,中间慢慢加速,到终点最快。。
// 可以看下面的图表。
tween.easing(TWEEN.Easing.Quadratic.In)

案例图表

image.png

如何自定义缓动动画?

  • 略,没有看懂。。
  • 可以查看案例代码。

案例图表

image.png

tween对象回调函数

可以在tween对象的生命周期内调用!如果对象的修改,需要通过set函数,就可以使用回调函数了!

举个例子。

  • 使用 onUpdate()
  • 在回调函数中,用set方法。

image.png

  • 使用 onStart()
  • 动画开始时,播放音乐

image.png

onStart

运行时间

  • 在启动start()方法之前 // 这样所有的开始都同步了!
  • delay()方法之后!// 当然应该在延迟之后执行了。。
  • 如果tween对象,启用repeat()方法,不起作用
  • 适用场景 - 同步所有需要一起执行的动画!

onStop

运行时间

  • 通过stop()显示停止动画时执行!, 一定要启动stop方法!
  • 不会在动画结束执行
  • 不会在链式调用下一个tween对象时执行!

onUpdate

运行时间

  • 只要动画执行就会执行!

onComplete

运行时间

  • 动画正常结束的时候执行,(没有调用stop方法。。)

onRepeat

运行时间

  • 动画完成,即将进行重复动画的时候执行!!

tween对象进阶

相对参数!

  • 主要用在to方法中的,看这里的"+"号
  • 计算位置不同!

image.png

嵌套对象!

  • Tween.js可以修改嵌套对象内的值
var nestedObject = {scale: {x: 0, y: 0}, alpha: 0}
var tween = new TWEEN.Tween(nestedObject).to({scale: {x: 100, y: 100}, alpha: 1})

to方法中,使用数组

  • 使用数组,可以在动画执行周期内,控制移动位置
// 运行开始,在0的位置,时间走到一半,在-100,终点在100
var tween = new TWEEN.Tween(relativeObj).to({x: [0, -100, 100]})

数组支持三种动画效果

03.gif

最佳使用规范

css动画

不要通过top 和left 来改变移动位置,它会导致重绘(改变样式)和回流(改变布局),很消耗性能。

// 通过 top 和left 来改变位置 - 不要这样!
var element = document.getElementById('myElement')
var tween = new TWEEN.Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).onUpdate(function (object) {
	element.style.top = object.top + 'px'
	element.style.left = object.left + 'px'
})

应该使用transform属性来改变位置!不会回流,硬件加速也可能支持。

var element = document.getElementById('myElement')
var tween = new TWEEN.Tween({top: 0, left: 0}).to({top: 100, left: 100}, 1000).onUpdate(function (object) {
	element.style.transform = 'translate(' + object.left + 'px, ' + object.top + 'px)'
})

如果我们的动画效果比较简单,通过cssanimationtransition就可以了,Tween.js主要用于复杂的动画效果。

垃圾回收

在使用onUpdate回调函数时,需要额外注意,它会在动画执行周期内,一直运行,如果在其中放入过多的操作,会占用大量的性能,需要保证onUpdate回调函数中的内容尽量轻便,不要有太多的操作。

crazy tweening

  • 这里好有意思,不常用
  • Tween.js可以把输入的数据,以不同的速率执行!
  • 文中举了个声音的例子
  • tween.audio (5013.es) - 使用tween.js修改声音的播放速率!!

03.gif

推荐案例

官方案例代码

image.png

Threejs!

03.gif

总结

翻译文档,是一个很棒的学习方法啊!

整理一下内容!

  • 我们在一开始,了解了Tween.js的运行流程,需要newto(), start(), TWEEN.update()

  • 然后学习了Tween.js的方法【start(), stop(), update()等】,和回调函数【可以控制的细节更多!,onStart(), onStop(), repeat(), yoyo()等】

  • 还有分组,设置缓动动画,最后给了一些实用小建议。

别让乌云遮住了天空的蓝,别让命运折返没桨的船,别让黑夜都落在你的臂弯,让我来与你作伴