前端攻城狮---js之动画运动框架

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gaoyouhuang/article/details/80784640

先来说说外链式的js的使用方式

<script type="text/javascript" src="animate.js"></script>这就是我们外链式的使用方法。

animate.js包含了我们动画运动框架的方法。

运动框架的编写

动画什么来的,在指定的时间内,通过定时器去不断的改变属性。

所以我们需要写一个animate方法,那么需要传入对象,属性,时间三个参数。

 // 封装运动函数
      function  animate(obj,endJson,time) {
        var start_list = {};//参数原始数据
        var change_list = {};//需要改变的值
        var change_now_list = {};//改变后的值
        var interval = 50;//频率
        var timers = time/interval;//改变总次数

        for(var k in endJson){
          start_list[k] = parseInt(fetchComputedStyle(obj,k));//获取到所需要改变属性目前的值
          change_now_list[k] = parseInt(fetchComputedStyle(obj,k));//每个属性改变后的值
        }
        for(var k in start_list){
            change_list[k] = (endJson[k]-start_list[k])/timers;//每个属性需要改变的值
        }
        var count = 0;
        var timer = setInterval(function(){
          for(var k in start_list){//设置定时器,让个个属性自增
            change_now_list[k] += change_list[k];
            obj.style[k] =  change_now_list[k]+"px";//改变属性的值,从而形成动画
          }
          count++;
          if (count==timers) {//达到改变次数的最大值得时候,取消定时器
            clearInterval(timer);
          }

        },interval);
      }

         // 定义函数
     function fetchComputedStyle(obj,property) {//能力检查,获取计算后属性
          if(window.getComputedStyle) {
               return getComputedStyle(obj)[property];
          } else {
              property = property.replace(/\-([a-z])/g,function(match,$1) {
                 return $1.substring(1,2).toUpperCase();
              });
              return obj.currentStyle[property];
          } 
     }

以上就是我们动画运动框架的初稿。

框架升级---透明度兼容

但是针对透明度这个特殊的属性,所以我们说获取透明度通过opacity获取可以解决兼容性问题,但是设置透明度我们就需要对浏览器进行分类。

所以修改在给属性赋值去改变的时候,加以判断

            if(k=="opacity") {
            	   	   obj.style[k] = xinhaoliang[k];
            	   	   obj.style.filter = "alpha(opacity="+xinhaoliang[k]*100+")";
            	   } else {
            	       obj.style[k] = xinhaoliang[k] + "px";
            	   }

若属性是opacity,则给opacity和filter都赋值做到兼容。

框架升级---回调

假如我们想知道动画什么时候结束,那么需要传入一个回调函数,可以在动画结束时去回调。那么我们就需要在传参的时候多传入一个callback参数。

 function  animate(obj,endJson,time,callback) ,就想着这样。

	count++;
            	if(count>=allcount) {
            		clearInterval(timer);
                // 解锁
                obj.isAnimated = false;
                // 执行回调
                callback.apply(obj);
            	}

我们可以在取消定时的时候去回调,当然回调的时候,我们可以回传参数。

apply call

我们先来看看外部调用的样式

          animate(oDiv,{"width":400,"height":400,"opacity":1},1000,function() {
         	  this.style.backgroundColor = "red";
         	  animate(this,{"left":500},500,function() {
         	  	  this.style.backgroundColor = "yellow";
         	  	  animate(this,{"top":600},300,function() {
         	  	  	   this.style.backgroundColor = "blue";
         	  	  	   animate(this,{"left":40},500,function() {
         	  	  	   })
         	  	  })
         	  })
         });

上面有四个动画,每一个动画都是在上一个动画调用好之后,再去调用。

我们都知道,第一个参数是我们需要改变属性的对象,但是在回调的函数中我们是通过this的方式去传递,那么这个this指向的是谁?这在在后续js对象中会讲到,animate()=window.animate(),所以方法里面的this理应指向window,但是我们通过apply的方式给方法指向了一个this,所以此时的this是oDiv,

apply()

        第一个参数表示指向的对象,第二个参数表示回传的参数,是一个数组。

call()

        第一个参数表示指向的对象,第二个第三个...表示回传的参数。

<script type="text/javascript">
	   function sum(x,y,z) {
	   	    console.log(x+y+z);
	   	    console.log(this);
	   }
	   sum.call(oDiv[0],2,3,4);
	   sum.apply(oDiv[0],[5,6,7]);
	</script>

框架升级---函数节流

试问一下,我们有一个需求通过点击事件去触发一个定时器,如果我们触发定时器的之前没有去清除定时器,那么定时器会叠加,要是定时器里有动画那么会越来越快。所以为了防止该情况,我们需要函数节流,也可以理解为锁。

所以我们可以改对象添加一个参数,来表示动画是否在进行,若在进行则去return。

在函数的最先面给函数添加参数obj.isAnimated = true;函数结束后obj.isAnimated = false;

完整代码

最后附上完整的代码

// 封装运动函数
	    function  animate(obj,endJson,time,callback) {
            if(obj.isAnimated){
              return;
            }
            obj.isAnimated = true;
            var start = {}; // 记住参与运动属性的初始值
            // 循环得到最终状态json的属性,这些属性就是参与运动的属性 
            for(var k in endJson) {
            	 start[k] = parseFloat(fetchComputedStyle(obj,k));
            }

            var stepJson = {}; // 记住运动属性的步长
            var xinhaoliang = {};

            for(var k in start) {
            	 xinhaoliang[k] = start[k]; 
            }

            var interval = 50;
            var allcount = time/interval;
            var count = 0;
            // 得到步长
            for(var k in endJson) {
            	endJson[k] = parseFloat(endJson[k]);
            	stepJson[k] = (endJson[k] - start[k])/allcount;
            }

            // 运动
            var timer = setInterval(function() {
            	for(var k in xinhaoliang) {
            	   xinhaoliang[k] += stepJson[k];
            	   if(k=="opacity") {
            	   	   obj.style[k] = xinhaoliang[k];
            	   	   obj.style.filter = "alpha(opacity="+xinhaoliang[k]*100+")";
            	   } else {
            	       obj.style[k] = xinhaoliang[k] + "px";
            	   }
            	}

            	count++;
            	if(count>=allcount) {
            		clearInterval(timer);
                // 解锁
                obj.isAnimated = false;
                // 执行回调
                callback.apply(obj);
            	}

            }, interval);
            
	    }

	       // 定义函数
	   function fetchComputedStyle(obj,property) {
          // 用户输入的属性有两种情况 一种驼峰式一种是连字符写法
          //高版本下 paddingLeft -------> padding-left
          if(window.getComputedStyle) {
          	  /*property = property.replace(/([A-Z])/g,function(match,$1) {
                 return "-"+$1.toLowerCase();
          	  });*/
          	  //console.log(property);
          	  return getComputedStyle(obj)[property];
          } else {
          	  // padding-left------>paddingLeft
          	  property = property.replace(/\-([a-z])/g,function(match,$1) {
                 return $1.toUpperCase();
          	  });
          	  return obj.currentStyle[property];
          } 
	   }
js的动画运动框架已讲完,接下来会来讲jquery,如有表达错的请谅解,并请提出指出,且修改错误,望能共同进步。


猜你喜欢

转载自blog.csdn.net/gaoyouhuang/article/details/80784640