英文单词 tween 的一个意思是“在……之间”,Tween.js 实现的就是对象属性值从 a 到 b 的变化。简言之,Tween.js 是一个模块化的JS补间动画库,轻量级(30来KB)且开源免费,用于创建指定属性值的变化、并利用变化的属性值为对象创建平滑的动画提供简洁明快的实现机制。
要使用 tween 库,首先需要在 type="module" 的 script 标签中使用 import 导入 tween 库模块文档:
<script type="module">
import TWEEN from 'https://638183.freep.cn/638183/3dev/examples/jsm/libs/tween.module.js';
//... 其它代码
</script>
上述资源库是 ThreeJS 作为扩展库而收录的tween模块文档,版本号为 23.1.1,并非最新。需要了解或获取最新版本的可访问 tween.js官网 。注意上面我们是从 tween 库资源导入了TWEEN 对象,该对象是我们后续使用的依据,比如创建一个后续要改变的对象单个或多个属性值,我们可以使用它的 Tween 方法,TWEEN.Tween(参数) :
const vals = { x: 0, y: 0 }; // 需要改变的属性值初始值 :使用JS对象的键值对表示
const tween = new TWEEN.Tween(vals); // 实例化一个 TEEEN 对象,命名为 tween,该对象针对 vals 开展工作
tween 就是一个实例化的 TWEEN 对象,通过它、对事先声明的变量 vals 的处理可以改变 vals.x 和 vals.y 的值,并可设置和控制 vals 作用对象的动画。首先,我们要让 vals 里面的数值产生变化,用 to 方法:
// 在2000毫秒的时间内令 vals 的值变为
tween.to({ x: 600, y: 460 }, 2000);
然后将 tween 改变的值作用于具体的对象,例如一个 id="box" 的绝对定位的 div 元素,我们通过 vals 记录的 x、y 值去驱动 div 的 left 和 top 即可,紧跟着是启动动画:
// 在 onUpdate 方法中驱动盒子CSS的left和top值
tween.onUpdate( () => {
box.style.left = vals.x + 'px';
box.style.top = vals.y + 'px';
};
// 用 start() 方法开启动画
tween.start();
以上,完成了动画机制,算是准备就绪,但要真正让 box 动起来,还需要一个全局的TWEEN.update(); 指令,指令放在一个函数中,函数则通过请求关键帧动画 requestAnimationFrame() 反复调用:
// 持续运行动画函数
const animate = () => {
TWEEN.update(); // 全局更新 tween 数据指令
requestAnimationFrame(animate); // 通过请求关键帧动画的API递归调用函数
};
animate(); // 运行动画
以下,我们将上述代码整合起来,激动人心的时刻立马到来:
<div id="box" style="position: absolute; width: 100px; height: 100px; background: tan;"></div>
<script type="module">
import TWEEN from 'https://638183.freep.cn/638183/3dev/examples/jsm/libs/tween.module.js';
const vals = { x: 0, y: 0 }; // 需要改变的属性值初始值
const tween = new TWEEN.Tween(vals); // 实例化一个 TEEEN 对象,该对象针对 vals 开展工作
tween.to({ x: 600, y: 460 }, 2000); // 在2000毫秒的时间内持续更新 vals 值到花括号里的设定
// 在 onUpdate 方法中驱动盒子CSS的left和top值
tween.onUpdate( () => {
box.style.left = vals.x + 'px';
box.style.top = vals.y + 'px';
});
tween.start(); // 开启动画
// 持续运行动画函数
const animate = () => {
TWEEN.update(); // 全局更新 tween 数据指令
requestAnimationFrame(animate); // 请求关键帧动画递归调用函数
};
animate(); // 运行动画
</script>
运行代码
可以看出,tween 先是改变一个JS对象(vals)里面的值(x和y),例如上例的vals = {x: 0, y: 0}; 中的 x 和 y,接着通过 onUpdate() 方法将改变中的 x 和 y 的值持续作用于指定的HTML元素即 id="box" 的 div,再辅以其它指令最终实现了 div 的位置移动动画。tween 能做到的和能做到的程度不止这些,以下例子我们将让 div 从左上角移动到右下角然后返回,到右下角时div宽高尺寸变为最大,动画反复运行并可暂停、继续:
<div style="position: absolute; width: 100%; margin: 10px; text-align: center;">点击页面可控制动画</div>
<div id="box" style="position: absolute; width: 100px; height: 100px; background: tan;"></div>
<script type="module">
import TWEEN from 'https://638183.freep.cn/638183/3dev/examples/jsm/libs/tween.module.js';
const vals = { x: 10, y: 10, w: 40, h: 40 }; // 初始化要改变的css属性值
const target = {x: window.innerWidth - 120, y: window.innerHeight - 120, w: 100, h: 100}; // css属性目标值
// 下面以链式写法创建tween动画机制
const tween = new TWEEN.Tween(vals)
.to(target, 3000)
.onUpdate( () => {
box.style.cssText += `
transform: translate(${vals.x}px, ${vals.y}px);
width: ${vals.w}px;
height: ${vals.h}px;
`
})
.easing(TWEEN.Easing.Quadratic.Out) // 缓动方式
.repeat(Infinity) // Infinity表示无限重复(支持正整数)
.repeatDelay(1000) // 重复间隔时间(毫秒)
.yoyo(3000) // 反向运行(时间毫秒,设置了repeat才会生效)
.start();
// 持续运行动画函数
const animate = () => {
TWEEN.update();
requestAnimationFrame(animate);
};
// 页面点击事件 :开始(启动)和暂停动画
document.onclick = () => {
if (!tween.isPlaying()) return tween.start(); // 如果动画尚未开始则开启动画
tween.isPaused() ? tween.resume() : tween.pause(); // 暂停或继续动画
};
animate();
</script>
运行代码
上面的代码实现了一个相对复杂的可控动画,如你所见,只要愿意,还可以做出更为精彩美妙的动画,前提是得稍微研究一下 tween.js 到底提供了多少功能,可以查阅中文版 tween.js 用户指南 以获取更多的tween相关知识。作为初探,我们点到为止,但请相信,ThreeJS 能将其作为扩展库收入囊中,tween.js 绝非等闲之辈。