javascript简易缓动插件

最近,同事在做一个项目的时候,有个需求,需要一款动画库来支持,要求如下:

  1. 可以开始、暂停(线性、非线性tween都支持)、继续、结束
  2. 支持多个样式并行
  3. 最好不依赖于某个框架下运行
  4. 文件尺寸越小越好

他找了一下现有的一些插件或者库,鲜有能满足或者比较均衡的,我在这个要求下,写了一个比较简陋的动画组件,基本满足了这个需求。先上代码

html部分:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>animate</title>
    <script type="text/javascript" src="tangram-1.5.0.core.js"></script>
    <script type="text/javascript" src="jquery.min.js"></script>
    <style>
    html,body,ul,li{padding:0;margin:0;}
    #anim{width:50px;height:50px;background:red;position:absolute; top:30px;left:0;}
    </style>
</head>
<body>
<div>
    <input type="button" value="start" onclick="an.start()" />
    <input type="button" value="pause" onclick="an.pause()" />
    <input type="button" value="resume" onclick="an.resume()" />
    <input type="button" value="stop" onclick="an.stop()" />
    <a target="_self" id="demolink" href="animate.html?demo=1" />auto start,pasue,then resume</a>
</div>
<div id="anim"></div>
</body>
</html>

animate部分:

function animate(options){
    this.from = options.from;//如果没有from,就计算出from
    this.to = options.to || {};
    this.onStart = options.onStart || empty;//以下是一些回调函数,就不采用事件机制了
    this.onStop = options.onStop || empty;
    this.onAnimate = options.onAnimate || empty;
    this.onContinue = options.onContinue || empty;
    this.onPause = options.onPause || empty;

    var element = options.element;
    var duration = options.duration || 300;//变化的总时长,单位是ms
    var pending = false;//是不是已经暂停了,如果还木有开始的话,该值也是true
    var timer = null;
    var mixin = options.mix;
    var defaultState = this.from || getState(element, this.to);//原始的数据
    var thiz = this;

    //获取最初始的样式
    function getState(ele, targetStyles){
        var obj = {};
        var i = 0;
        for (var p in targetStyles)
        {
            i++;
            obj[p] = parseFloat(mixin.getStyle(ele, p));
        }
        if(i == 0){
            return null;
        }
        return obj;
    }
    
    function empty(){}

    function animate(from, to, elapse){
        var startTime = (new Date).getTime() + (elapse ? - elapse : 0);//如果有第三个参数,证明是从一个暂停开始的,那么就设置startTime为当前时间减去暂定时已经逝去的时间,如果只有两个参数,那么逝去时间就是0
        timer = setInterval(function(){
            var endTime = (new Date).getTime();
            if(endTime - startTime < duration){
                thiz.onAnimate();
                currentElapse = endTime - startTime;
                for(var p in from){
                    if(from.hasOwnProperty(p)){
                        var currentPropertyStyle = mixin.compute(currentElapse, from[p], to[p]-from[p], duration);
                        mixin.setStyle(element, p, currentPropertyStyle);
                    }
                }
            }
            else{
                thiz.stop(thiz.to);
            }
        }, 16);
    }

    this.start = function(){
        if(pending){
            this.resume();
        }
        else{
            this.onStart();
            animate(defaultState, this.to);
        }
    }

    this.stop = function(){
        clearInterval(timer);
        var styles = this.to;

        for(var p in styles){
            if(styles.hasOwnProperty(p)){
                mixin.setStyle(element, p, styles[p]);
            }
        }
        this.onStop();
    }

    this.pause = function(){
        clearInterval(timer);
        pending = true;
        this.onPause();
    }

    this.resume = function(){
        pending = false;
        this.onContinue();
        animate(defaultState, this.to, currentElapse);
    }
}

使用部分:

var mixinT = {
    getStyle:baidu.dom.getStyle,
    setStyle:baidu.dom.setStyle,
    compute:function(t, b, c, d){
        //return t*c/d + b;
        if (t==0) return b;
   if (t==d) return b+c;
   if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
   return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
    }
};
var mixinJQ = {
    getStyle:function(ele, styleName){
        return $(ele).css(styleName);
    },
    setStyle:function(ele, styleName, styleValue){
        $(ele).css(styleName, styleValue);
    },
    compute:function(t, b, c, d){
        return b+ t*c/d;
    }
};

var an = new animate({
    element:document.getElementById('anim'),
    //from:{'width':100, 'height':100, left:0, top:30},
    to:{left:500},
    mix:mixinT,
    duration:2000
});


if(/demo=1/.test(location.search)){
    var demolink = baidu.g('demolink');
    demolink.href= 'animate.html';
    demolink.innerHTML = 'back';
    an.start();
    setTimeout(function(){
        an.pause();
        resume();
    }, 1200);

    function resume(){
        setTimeout(function(){an.resume()}, 1000);
    }    
}

上面是一个完整demo的代码。做几点说明:

  1. 代码尺寸足够小了,一共才100行,gzip后连1k都不到。
  2. 满足了可以start、pause、resume、stop的需求,赠送了几个回调函数:D。
  3. 可以支持多个样式一起变化。
  4. 采用了一个mixin变量,传进来三个函数需要在执行动画时的操作,getStyle、setStyle、compute,我感觉这三个确实和用户的选择有关系,前两个可能和框架有关,第三个和用户采用的变化计算方式有关,之所以传进去四个参数,主要是和主流的tween类能适应起来,可以参考http://www.robertpenner.com/easing/http://www.actionscript.org/resources/articles/170/1/Flash-MX-2004-Undocumented-TweenEasing-Classes-Documented/Page1.html。我给的例子用了tangram和jquery俩类库,分别对应了两个mixin对象,做一下简单的适配,就能用了。
  5. 一些“私有”变量和函数放闭包里了,这样初始化一个animate的时候,对象是干净的,但是缺点就是占用内存多了,每个实例都维护自己的方法。
  6. 使用的时候,可以不提供options.from,函数会根据额options.to来计算from中对应样式的值,这很大程度上依赖于mixin提供的方法够不够强大,所以这一块还是有bug 的,不过,80%的功能够用了。麻雀虽小,五脏俱全了。

最后,给出一份完整的代码

转载于:https://www.cnblogs.com/jppartner/archive/2012/02/16/2353440.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值