blogs icon indicating copy to clipboard operation
blogs copied to clipboard

Tween.js 的使用

Open forever-z-133 opened this issue 7 years ago • 0 comments

Tween.js 只有 5.6k,拿来做动画是一个不错的选择。 是 CreateJS(神器)旗下的一个子项目,受众庞大,值得一学。

<script src="https://cdn.bootcss.com/tween.js/r14/Tween.min.js"></script>

以下代码请注意 TWEEN / Tween / tween 三者的区别

基础

写个小 demo 先来感受一下 Tween.js 的魅力: 就是以下这样简单的 4 步完成值的匀速变化。

// 指定动画对象
var pos = {x: 0, y: 0};
var tween = new TWEEN.Tween(pos);

// 指定动画目标 和 运行时间
tween.to({x: 200}, 1000);

// 启动 tween
tween.start();

// 动画不断更新
animate();
function animate() {
  TWEEN.update();
  requestAnimationFrame(animate);
}

// 监听动画变动
tween.onUpdate(function(){
  console.log(this.x)
});

动画流程

update 即更新一次,如果传入某毫秒值作为参数,则一直更新该时间对应的动画值,试一次就懂了。 stop 即可暂停动画,再次 start 则从暂停处继续动画。 start 传入某毫秒值作为参数的话,代表动画将从该时间开始。

动画队列

TWEEN.getAll() 获取动画队列,数组类型,动画完成就会清出队列。 TWEEN.removeALL() 清空队列。 TWEEN.add(B) 添加一个队列,与 chain 不同在于 add 是同时运行的。 TWEEN.remove(B) 把 B 从队列中清除。

动画队列拼接

A.chain(B) 可以连接多个动画,B 将在 A 结束之后运行。

  • B 的定义最好写在 A.start() 之前
  • 如果同时写 B.start(),会既立刻运行,也在 A 结束时运行。
  • B 的回调是独立的,所以除了 A.onUpdate,B.onUpdate 也要写
  • B 与 A 操作同一个对象是没问题的

动画循环

repeat 循环动画,且 chain 还是跟在 repeat 最终结束之后。 yoyo 需与 repeat 合用,且需传入非 0 参数,偶数次动画会反向运行。

tween.repeat(1);  // 将运行总共 2 次
tween.repeat(Infinity); // 无限循环
tween.yoyo(1);  // 一次正序一次倒序的运行

动画延迟

delay 延迟运行。概念比较好理解,但眉头一皱,发现此事并不简单。

  • 放在 start 前面还是后面,效果是不同的
  • repeat 时,是延迟后再运行的,即每次重复都有延时

动画缓冲

TWEEN.Easing 下有 Linear, Quadratic, Cubic, Quartic, Quintic, Sinusoidal, Exponential, Circular, Elastic, Back, Bounce 这 11 种类型的缓动类型。 除 Linear 只有 None 外,其他都含有 In, Out, InOut 3 种缓动效果。所以共计 31 种。 easing 方法传入以上参数,即可实现各种节奏效果。

tween.easing(TWEEN.Easing.Linear.None);
tween.easing(TWEEN.Easing.Bounce.InOut);

自定义缓动函数则传入一个方法,返回该时间帧应该改用的时间帧即可

tween.easing(function(k){
  console.log(k);   // k 为时间进度,范围 [0, 1)
  return Math.floor(k * 10) / 10;
});

具体的效果区别,可参见此 DEMO右键在新标签打开连接

动画回调

  • tween.onStart
  • tween.onStop
  • tween.onUpdate
  • tween.onComplete

自己写的动画工具

曾经为了简化写动画的过程,也搞过一个这样的动画类工具,发出来缅怀一下。

!(function(){
  // 判断类型
  window.Type = function(obj) {
    var typeStr = Object.prototype.toString.call(obj).split(" ")[1];
    return typeStr.substr(0, typeStr.length - 1).toLowerCase();
  }

  // 区间内持续时间的变化
  window.smooth = function(fn, duration, option, finish) {
    var type, per, now = Date.now(), Timer, count = 0;
       
    var _optionType = Type(option);
    if (_optionType === 'boolean') { // 循环模式
      type = 'infinite';
      duration = duration || 25;
    } else if (_optionType === 'number') { // 限定次数
      type = 'remain';
      duration = duration || 25;
      var remain = option;
    } else {    // 运行一次,但 duration 期间按设备性能持续运行 fn
      type = 'animate';
      duration = duration || 1000;
      if (option) finish = option;
    }

    _run();
    function _run() {
      per = Math.min(1, (Date.now() - now) / duration);
      if (per < 1) {
        if (type === 'animate') fn(per, ++count);
        Timer = requestAnimationFrame(_run);
      } else {
        if (type === 'animate' && finish) finish();
        if (type === 'infinite' || count < remain) {
          now = Date.now();
          fn(++count);
          if (count === remain && finish) finish()
          Timer = requestAnimationFrame(_run);
        } else {
          cancelAnimationFrame(Timer);
        }
      }
    }

    return {
      stop: function() {
        cancelAnimationFrame(Timer);
      }
    }
  }
})()

个人觉得写的还是不错的,我也在经常使用, 只比 Tween.js 少了两个回调和 easing 而已。

之后如何使用,就看你的项目需求咯,加油大宝贝。

forever-z-133 avatar Sep 14 '17 04:09 forever-z-133