实现一个简单的缓动动画

428 阅读1分钟
<div id="div" style="position: absolute; background-color: skyblue;">我是div</div>
/*  缓动动画算法
* @param { number } t (当前已消耗时间)    
* @param { number } b beginning value(初始值)   
* @param { number } c change in value(变化量)    
* @param { number } d (动画总时间)
*/ 
var tween = {
    linear: function (t, b, c, d) {
        return c * t / d + b;
    },
    easeIn: function (t, b, c, d) {
        return c * (t /= d) * t + b;
    },
    strongEaseIn: function (t, b, c, d) {
        return c * (t /= d) * t * t * t * t + b;
    },
    strongEaseOut: function (t, b, c, d) {
        return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
    },
    sineaseIn: function (t, b, c, d) {
        return c * (t /= d) * t * t + b;
    },
    sineaseOut: function (t, b, c, d) {
        return c * ((t = t / d - 1) * t * t + 1) + b;
    }
};

var Animate = function (dom) {
    this.dom = dom                  // 进行动画的 dom 节点
    this.startTime = 0              // 动画开始时间
    this.startPos = 0               // dom 的初始位置
    this.endPos = 0                 // dom 的目标位置
    this.propertyName = null        // dom 节点需要被修改的 css 属性名
    this.easing = null              // 缓动算法
    this.duration = null            // 动画持续时间
}

Animate.prototype.start = function (propertyName, endPos, duration, easing) {
    this.startTime = +new Date;     // 动画起始时间
    this.startPos = this.dom.getBoundingClientRect()[ propertyName ]    // dom 节点初始位置
    this.propertyName = propertyName    // dom 节点需要被改变的 CSS 属性名
    this.endPos = endPos    // dom 节点目标位置
    this.duration = duration    // 动画持续时间
    this.easing = tween[ easing ]   // 缓动算法

    var self = this
    var timeId = setInterval( function() {
        if (self.step() === false) {
            clearInterval( timeId )
        }
    }, 1000 / 60);
}

Animate.prototype.step = function () {
    var t = +new Date;      // 获取当前时间
    if (t >= this.startTime + this.duration) {
        this.update( this.endPos )  // 超过时间时,修正目标最终位置
        return false
    }
    var pos = this.easing( t - this.startTime, this.startPos, 
        this.endPos - this.startPos, this.duration)
    // pos 为小球当前位置
    this.update( pos )  
}

Animate.prototype.update = function (pos) {
    this.dom.style[ this.propertyName ] = pos + 'px'
}

var div = document.getElementById( 'div' );
var animate = new Animate( div );
animate.start( 'left', 500, 1000, 'sineaseOut' );
// animate.start( 'top', 500, 1000, 'easeIn' );