一个前端博客(10)——动画

最简单的运动

var box = document.getElementById("box");
setInterval(function(){
      box.style.left = box.offsetLeft + 1 + ‘px’;
},50);

创建Tar的运动效果方法animate:

Tar.prototype.animate = function(obj){
      for(var i = 0; i < this.elements.length; i++) {

      }
      return this;
}

首先我们说一下参数obj。

参数obj是一个对象

{
    "attr"  : "",//动画的属性,参数:x,y,w,h。x == left, y == top, w ==width, h == height,默认为left
    "start" : "",//运动的开始位置,默认为当前的位置
    "t"     : "",//运动的时间,默认为30
    "step"  : "",//速度,默认为10
    "target": "",//目标位置,*px
    "alter" : "",//增量,*px
    "speed" : "",//缓冲值,默认为6
    "type"  : ""//是否缓冲,1为缓冲,0为不缓冲。默认为缓冲
}

对应这些参数我们需要创建相应的变量。通过三元操作符,来赋予各个变量的值。

比如第一个参数attr:

var attr = obj['attr'] == 'x' ? 'left' : obj['attr'] == 'y' ? 'top' : obj['attr'] == 'w' ? 'width' :
           obj['attr'] == 'h' ? 'height' : 'left';

类似的:

var start = obj['start'] != undefined ? obj['start'] : getStyle(element, attr);
var t     = obj['t'] != undefined ? obj['t'] : 30;
var step  = obj['step'] != undefined ? obj['step'] : 10;

不过这里:

var target = obj['target'];
var alter  = obj['alter'];

由于他们不能同时存在,也不能同时不存在。当增量alter存在的时候,通过 "起始量" + "增量" 就可以得到 "目标量".而有了目标量,增量就可以不用管了。于是有了下面的代码:

if(alter != undefined && target == undefined) {
    target = alter + start;
}else if(alert == undefined && target == undefined) {
    throw new Error('alter增量或者target目标量必须传递一个!');
}

最后两个参数:

var speed = obj['speed'] != undefined ? obj['speed'] : 6;
var type = obj['type'] == 0 ? 'constant' : obj['type'] == 1 ? 'buffer' : 'buffer';

参数问题解决了,下面要解决的是关于step的问题。如果目标比开始的位置要大,那么step应该为正的,如果目标比开始的位置小,那么step应该为负值。然而我们传递的参数一直都是正值。所以这里我们需要判断一下,来决定step的值为正还是负。

if(target < start) step = -step;

然后我们开始第一步运动,就是让元素从start的位置开始,并且我们要清除全局的timer定时器,因为我们后面就是通过timer来实现运动的,这个看前面的运动基本原理就知道了,清除它是为了方式产生多个定时器而造成我们不想要的效果。

elment.style = start + 'px';
clearInterval(window.timer);

接下来我们开始定时器的部分:

timer = setInterval(functtion(){}, t);

运动的核心就是element.style[attr] = getStyle(element,attr) + step + "px";

运动停止的条件是:

如果step>0,那么当当前的位置大于目标的时候停止。不过这会出现奇怪的现象:比如向右移动会在最后向左运动一下。原因很简单,走过头了。所以这里我们不采用这种方式来判断。而是这样:

如果step>0,那么当当前位置与目标位置的差距的绝对值 小于等于step的时候,元素直接到达目标位置,并且停止运动。因为最后一步是正好到达。所以不会有奇怪的效果出现。同理,如果step<0,那么当当前位置与目标位置的差距小于等于step的绝对值的时候(PS:此时step为负值),元素直接到达目标位置,并且停止运动。

这里还有一个问题,step可不可能为0呢?这个我们稍后再说。

停止运动,就是将元素设置为目标位置后清除定时器。我们可以把它封装起来,当做一个函数。

function setTarget() {
    element.style[attr] = target + 'px';
    clearInterval(timer);
}

那么定时器里的代码如下:

if(step > 0 && Math.abs(getStyle(element, attr) - target) <= step) {
        setTarget();
    }else if(step < 0 && (getStyle(element, attr) - target) <= Math.abs(step)) {
        setTarget();
    }else {
        element.style[attr] = getStyle(element,attr) + step + "px";
    }

下面我们来说一下step==0的问题。这里我们一直没有用到缓冲变量。我们先讲一下缓冲的实现:

这里我们默认缓冲为由快到慢,一般来说这个速率是通过每次运动后, temp = 目标位置当前位置差距 除以缓冲值speed 得到的。又由于step有正值和负值,所以通过判断step的正负,分别使用Math.ceil向上取整和Math.floor向下取整。正值的时候使用Math.ceil,小数部分进一位。负数的时候使用Math.floor,小数部分进一位。这样就不会导致结束运动的时候不流畅突兀的感觉。

所以代码如下:

if(type == 'buffer') {
    var temp = (getStyle(element, attr) - target) / speed;
    step = step > 0 ? Math.ceil(temp) : Math.floor(temp);
}

由于缓冲的原因,step的值是改变的,会有某个时刻,step的值为0。这个时候,就直接调用setTarget()就可以了。

最后代码如下:

Tar.prototype.animate = function() {
    for(var i = 0; i < this.elements.length; i++) {
        var element = this.elements[i];
        var attr  = obj['attr'] == 'x' ? 'left' : obj['attr'] == 'y' ? 'top' : obj['attr'] == 'w' ? 'width' :
                    obj['attr'] == 'h' ? 'height' : 'left';
        var start = obj['start'] != undefined ? obj['start'] : getStyle(element, attr);
        var t     = obj['t'] != undefined ? obj['t'] : 30;
        var step  = obj['step'] != undefined ? obj['step'] : 10;
        var target= obj['target'];
        var alter = obj['alter'];
        if(alter != undefined && target == undefined) {
            target = alter + start;
        }else if(alert == undefined && target == undefined) {
            throw new Error('alter增量或者target目标量必须传递一个!');
        }
        var speed = obj['speed'] != undefined ? obj['speed'] : 6;
        var type = obj['type'] == 0 ? 'constant' : obj['type'] == 1 ? 'buffer' : 'buffer';

        if(target < start) step = -step;
        this.elements[i].style = start + 'px';
        clearInterval(window.timer);
        timer = setInterval(function() {
            if(type == 'buffer') {
                var temp = (getStyle(element, attr) - target) / speed;
                step = step > 0 ? Math.ceil(temp) : Math.floor(temp);
            }
            if(step == 0){
                setTarget();
            }
            else if(step > 0 && Math.abs(getStyle(element, attr) - target) <= step) {
                setTarget();
            }else if(step < 0 && (getStyle(element, attr) - target) <= Math.abs(step)) {
                setTarget();
            }else {
                element.style[attr] = getStyle(element,attr) + step + "px";
            }
        }, t);
        function setTarget() {
            element.style[attr] = target + 'px';
            clearInterval(timer);
        }
    }
    return this;
}

 

posted @ 2015-11-03 15:02  targeral  阅读(131)  评论(0编辑  收藏  举报