首页 » JavaScript » JS 动画初探(上)

最后更新于 2018年12月14日

我们先来做一个简单的动画,让一个div横向移动。

既然是要横向移动,我们就要对这个div的left属性进行设置,那么这里就可以使用间歇调用的方式不断的去增加left的值,然后到了某一个指定的位置时停止。

html部分:

<div id="box"></div>

css部分:

#box {
    width: 100px;
    height: 100px;
    background-color: red;
    position: absolute;
    top: 300px;
    left: 300px;
}

js部分:

//调用代码
$(function(){
  $('#box').animation('left',10,600,50);
});

//封装库
Base.prototype.animation = function(attr,step,end,time) {
    for(var i = 0;i<this.arr.length;i++){
       var element = this.arr[i];
       var timer = setIntarval(function(){
           element.style[attr] = parseInt(getStyle(element,attr)) + step + 'px';
           if(parseInt(getStyle(element,attr)) >= end) {
                element.style[attr] = end + 'px';
                clearInterval(timer);
                      }
       },time);
    }
    return this;
}

//获取计算后的style
function getStyle(arr,attr) {
    if(typeof window.getComputedStyle != 'undefined') {
        return window.getComputedStyle(arr,null)[attr];
    }else if(typeof arr.currentStyle != 'undefined') {
        return arr.currentStyle[attr];
    }
}

通过传入方向,每次移动多少,最终的位置,超时调用的间隔时间,来进行移动,这样形成了一个初步的移动。

其中,在if判断当前位置已经>=最终位置时,我们让他的style[attr] = end,这样可以防止,当移动的距离超出一点的时候不会停在那里不动,导致有一些差异,而且这个超出部分移动的时间是和 element.style[attr] = parseInt(getStyle(element,attr)) + step + 'px';共用的,也就是说同时完成,这样不会造成div移动超出后会有一个往回走的不自然感。

为什么会超出,那是因为你不可能每次设置的都是可以相加然后等于end的值吧,就好像你每次移动7px,你能最终通过7+7+7+7....这样加下去,最终等于50吗,这明显不可能的事情,所以if判断后才会需要重新设置style[attr] = end。

重新设置后再将超时调用删除。

getStyle(arr,attr)返回的是计算后的值,但是他会带单位,返回的是300px,这是一个string类型,我们要将其转为数值,可以通过正则的方式匹配数字,然后Number(正则匹配的数字),转换为num类型,这里直接使用parseInt()转换,如果这个字符串开头就是数字,那么便会转换这个数字,其他的字符被忽略。

JS 动画初探1

简单的动画制作完毕,但是我们进行优化。

超时调用的时间一般来说都是固定的,而且数值过时间久了,根本不知道都代表什么意思,这里就要用键对值的形式传参,然后还要判断是往左还是往右。

判断往左往右

如果当前元素的位置大于移动的终点,那么就说明要往左,如果移动的终点大于当前位置,就是往右。

if(parseInt(getStyle(element,attr)) > end) step = -step;

通过键对值的方式传参

//调用代码
$(function(){
    $('#box').animation({
        'attr' : 'left',
        'step' : 7,
        'start' : 300,
        'end' : 50,
        'time' : 30
    })
});

//封装库
Base.prototype.animation = function(obj) {
    for(var i = 0;i<this.arr.length;i++){
        var element = this.arr[i];
        var attr = obj['attr'] != undefined ? obj['attr'] : 'left';
        var step = obj['step'] != undefined ? obj['step'] : 10;
        var start = obj['start'] != undefined ? obj['start'] : parseInt(getStyle(element,attr));        
        var time = obj['time'] != undefined ? obj['time'] : 50;
        var end = obj['end'];
        element.style[attr] = start + 'px';
        if(start > end) step = -step;
        var timer = setInterval(function(){
            element.style[attr] = parseInt(getStyle(element,attr)) + step + 'px';
            if(step > 0 && parseInt(getStyle(element,attr)) >= end) {
                element.style[attr] = end + 'px';
                clearInterval(timer);
            }else if(step < 0 && parseInt(getStyle(element,attr)) <= end) {
                element.style[attr] = end + 'px';
                clearInterval(timer);
            }
        },time)
    }
    return this;
}
//获取计算后的style
function getStyle(arr,attr) {
    if(typeof window.getComputedStyle != 'undefined') {
        return window.getComputedStyle(arr,null)[attr];
    }else if(typeof arr.currentStyle != 'undefined') {
        return arr.currentStyle[attr];
    }
}

通过键对值的方式传值,end的值是必须的,其他都通过三元的方式设置了备用的值,然后还添加了一个start的起始位置值,我们可以设置元素的起始位置。

然后就是考虑到往左移动的时候,step是负值,如果一直减下去会超出边框外,所以也要做个if判断,如果元素的位置已经小于end的值,说明已经往左移动过头了,所以也和上面一样, element.style[attr] = end + 'px';然后删除这个超时调用。

上面虽然都差不多了,但是end的设置还是差点意思,因为你要算好元素要移动到那个位置,而不能直接增加,比如我要移动20个像素,那么你就要计算一下,当前位置+20再填到end中去,这样太麻烦了。

增量移动

将end的判断改为:

var end = start + obj['end'];

这样每次只要填需要移动多久即可。

  • weixiao kaixin tushetou jingkong deyi fanu liezui liuhan daku ganga bishi nanguo lihai qian yiwen numu tu yi haixiu se fadai minyan hehe henkaixin huaji biyiyan kuanghan maimeng shui xiaku penqi zhangzui pen aini ye niu laji ok chigua renshi kongbu shuai xiaoxiese touxiao huaixiao jingnu chihuai kaisang xiaoku koubi zhuangbi lianhong kanbujian shafa zhijing xiangjiao dabian yaowan redjing lazhu rizhi duocang chixigua hejiu xixi xiaopen goukun xiaobuchu shenme wusuowei guancha lajing chouyan xiaochi bie zhadanzui zhadanxiao