js动画效果总结

js动画函数封装–单物体运动

  1. 对一个div进行宽高属性的变化,对透明度属性进行变化。

          *{margin: 0; padding: 0;}    /\*样式\*/    
          <div id="parent"><div id="son">分享</div> </div>    /*结构*/       
          #parent {position: relative; width: 200px; height: 200px; background-color: #f00; margin-left: -200px;}
          #son {position: absolute; width: 30px; height: 50px; background-color: green; top: 50%; right:-30px; transform: translateY(-50%); text-align: center; }  
           window.onload=function(){ //首先加载函数在dom加载后
           var parent=document.getElementById("parent"); //获得父级dom元素
           parent.onmousemove=function(){ //当鼠标在父级元素上移动时,触发事件
           move(10,0);    //move 函数对进行处理
           }
           parent.onmouseout=function(){ //当鼠标离开父级元素时,触发事件
           move(-10,-200);    }}  
           var timer=null; 
           function move(speed,target){
           clearInterval(timer); //每次在进入move之前都清除定时器
           var parent=document.getElementById("parent");
           timer=setInterval(function(){ //设置定时器
           if(parent.offsetLeft==target){ //假如满足条件,清除定时器
           clearInterval(timer);
           }else{ //否则进行进一步处理
              parent.style.marginLeft=parent.offsetLeft+speed+"px";
                }
       },30);
       }   /*js代码*/                                                                       

    这里可能像我这样的新手对 parent.offsetLeftmarginLeft对这些属性比较陌生,具体可以参考这篇文章 offsetLeft,有图有真相。

  2. 透明度属性的处理

       #opcity {width: 200px; height: 200px; background-color: #f00; filter: alpha(opacity=30); /*兼容IE9 以下*/opacity: 0.3; } /*样式*/
       <div id="opcity"></div> /*结构*/
       window.onload=function(){
           var opcity=document.getElementById("opcity");
           opcity.onmousemove=function(){
           move(100);    
           }
           opcity.onmouseout=function(){
           move(30);    
           }
       }
       var timer=null;
       var op=30;
       function move(arg){
            clearInterval(timer);
            var opcity=document.getElementById("opcity");
            timer=setInterval(function(){
             var speed=0;
             if(op<arg){
            speed=10;    
             }else {
            speed=-10;
             }
              if(op==arg){
                clearInterval(timer);
             }else {
                 op+=speed;
                 opcity.style.filter="alpha(opacity="+op+")"; /*兼容IE的写法*/
                 opcity.style.opacity=op/100;
             }
       },30);
       }   /*js代码*/

    这里的代码基本和上面基本上是一样的,主要是要对 opacity进行处理,这里在后面还有一种处理办法,由于opacity 传进来是0.3这样的小数,可以先用parseFloat()对opacity进行处理,然后在乘以100使其变成一个整数,然后在进行后面的处理。

js动画函数封装–多物体运动

div {width: 400px; height: 200px; background-color: yellow; border: 2px solid #666; margin-bottom: 20px;} /*样式*/

<div id="test"></div>
<div id="test1"></div>  /*结构*/

window.onload=function(){
        var test= document.getElementById("test");
        var test1= document.getElementById("test1");
        test.timer=null;
        test1.timer=null;
        test.onmouseover=function(){
           move(this,'width',200);
        }
        test.onmouseout=function(){
           move(this,'width',400);
        }
        test1.onmouseover=function(){
           move(this,'height',400);
        }
        test1.onmouseout=function(){
           move(this,'height',200);
        }
    }
    function move(obj,attr,target){
        clearInterval(obj.timer);
        obj.timer=setInterval(function(){
        var pa=    parseInt(getStyle(obj,attr));    
         var speed=(target-pa)/8;
         speed=(speed>0)?Math.ceil(speed):Math.floor(speed);
             obj.style[attr]=pa+speed+"px";            
     },30);
    }
    function getStyle(obj,attr){
        if(obj.currentStyle){
            return obj.currentStyle[attr]; /*IE 方法*/
        }else {
            return getComputedStyle(obj,false)[attr]; /*chrome ,ff*/
        }
    }  /*js代码*/
  1. 这里新封装一个函数,getStyle()用来获取DOM元素样式,对currentStylegetComputedStyle有疑问的可以参考一下张鑫旭大神的这篇文章currentStyle getComputedStyle,到这一步开始有进一步对函数的封装,记得开始的时候单物体运动的时候,只有一个属性,只需要传一个参数,对 opacity的处理大致也差不多,只是要多一点转化,对于多物体运动,属性的值是在变化的,而且test test1一个改变宽,一个改变高,所以可以对函数可以进一步封装,这里对于opacity处理是有问题的,需要在函数内部进行判断,选择不同的分支。这里还要注意的是定时器不能共用,要单独设置自己的定时器。

js动画函数封装–缓冲运动

基本结构和上面单物体结构相同

<script type="text/javascript">
     window.onload=function(){
        var parent=document.getElementById("parent");
        parent.onmousemove=function(){
        move(0);    
        }
        parent.onmouseout=function(){
        move(-200);    
        }
    }
    var timer=null;
    function move(target){
     clearInterval(timer);
     var parent=document.getElementById("parent");
     timer=setInterval(function(){
          var speed=(target-parent.offsetLeft)/20; //缓冲运动
          speed=(speed>0)?Math.ceil(speed):Math.floor(speed);
           if(parent.offsetLeft==target){
             clearInterval(timer);
          }else {
              parent.style.marginLeft=parent.offsetLeft+speed+"px";
          }
    },30);
    }

再单物体运动中,我们每次都是加上一个恒定大小的值,其实就是一个匀速运动,为了做一个缓冲运动,我们首先联想到火车进站的时候,一般都是先加速,在减速,最后慢慢加速离开,缓冲运动就类似这种情况parent.style.marginLeft=parent.offsetLeft+speed+"px";,通过传过来的目标参数与实际样式的值进行一个做差处理,然后除以一个数字,刚开始是极值,speed的值变化较大,到后面随着两值比较接近,speed越来越趋近与0,为了最后能达到目标值,要让speed变为1,再慢慢达到目标值,所以会使用Math.floor()和 Math.ceil()向上取整和向下取整函数,假如speed>0,则像上取整,假如speed<0,则向下取整,取值+1和-1.

js动画函数封装–单物体的多属性同时运动

<div id="test"></div>
div {width: 400px; height: 200px; background-color: yellow; border: 2px solid #666; margin-bottom: 20px; filter: alpha(opacity=30); /**兼容IE 6*/ opacity: 0.3;}
         window.onload=function(){
         var test= document.getElementById("test");
         test.timer=null;
         test.alpha=30;
         test.onmouseover=function(){
         move(this,{"width": 600, "height": 400, "opacity": 100});
        }
        test.onmouseout=function(){
          move(this,{"width": 400, "height": 200, "opacity": 30})
        }
}
      var flag=true;
      function move(obj,json,fn){
      clearInterval(obj.timer);
      obj.timer=setInterval(function(){
        for(attr in json){
          if(attr=="opacity"){
          var pa= parseFloat(getStyle(obj,attr))*100; 
          }else{
           var pa= parseInt(getStyle(obj,attr));
          }
          var speed=(json[attr]-pa)/8;
          speed=(speed>0)?Math.ceil(speed):Math.floor(speed);
          if(json[attr]!=pa){
              flag=false;
            }
        if(attr=="opacity"){
          obj.alpha+=speed;
          obj.style.filter="alpha(opacity="+obj.alpha+")";
          obj.style[attr]=(obj.alpha)/100;
          }else{
          obj.style[attr]=pa+speed+"px";
          }
    }
    if(flag){
      clearInterval(obj.timer);
      if(fn){
        fn();
      }
    }         
     },30);
}
function getStyle(obj,attr){
     if(obj.currentStyle){
        return obj.currentStyle[attr];
     }else {
        return getComputedStyle(obj,false)[attr];
     }
}

为了实现单物体的多属性同时运动,使用到json格式传参,然后对json里的每一个属性,在定时器里用for in循环进行遍历,用getStyle()对获取属性进行处理。

js动画函数封装–单物体的链式运动

   .clearfix:after {content: "."; display: block; clear: both; visibility: hidden; height: 0;}
   *{margin: 0; padding: 0;}
   #content {width: 660px; height: 210px; border: 2px solid #ccc; margin :20px auto; font-size: 0;}
   #content a {position: relative; display: inline-block; width: 120px; height: 80px;  text-align: center; font: bold 14px/1 Arial; color: #f3f3f3; text-decoration: none; border: 2px solid orange; margin: 10px 20px;}
   #content a:hover {color: orange;}
   #content a p {position: relative; margin-top: 10px; bottom: -45px;}
   #content a i {position: absolute; top: 5px; left: 40px; display: inline-block; filter: alpha(opacity=100); opacity: 1;}
   <div id="content">
    <a href="#">
        <i><img src="images/001.jpg" alt=""></i>
        <p>便民</p>
    </a>
    <a href="#">
        <i><img src="images/002.jpg" alt=""></i>
        <p>充值</p>
    </a>
    <a href="#">
        <i><img src="images/003.jpg" alt=""></i>
        <p>旅行</p>
    </a>
    <a href="#">
        <i><img src="images/004.jpg" alt=""></i>
        <p>缴费</p>
    </a>
    <a href="#">
        <i><img src="images/005.jpg" alt=""></i>
        <p>电影</p>
    </a>
    <a href="#">
        <i><img src="images/006.jpg" alt=""></i>
        <p>音乐</p>
    </a>
    <a href="#">
        <i><img src="images/007.jpg" alt=""></i>
        <p>教育</p>
    </a>
    <a href="#">
        <i><img src="images/008.jpg" alt=""></i>
        <p>能源</p>
    </a>
</div>
        window.onload=function(){
        var content= document.getElementById("content");
        var links= content.getElementsByTagName("a");
        for (var i = 0; i < links.length; i++) {
            links[i].onmouseenter=function(){
                var inode=this.getElementsByTagName("i")[0];
                inode.timer=null;
                inode.alpha=30;
                    move(inode,{marginTop:-40,opacity: 0},function(){
                        inode.style.marginTop=20+"px";
                        move(inode,{marginTop:5,opacity: 100});
                        });
            }
        }
    }
    //获取样式
    function getStyle(obj,attr){
        if(obj.currentStyle){
            return obj.currentStyle[attr];
        }else {
            return getComputedStyle(obj,false)[attr];
        }
    }
    //move 函数    
    function move(obj,json,fn){
    clearInterval(obj.timer);
    obj.timer=setInterval(function(){
    var flag=true;
    for(attr in json){
      if(attr=="opacity"){
      var pa= parseFloat(getStyle(obj,attr))*100; 
      }else{
       var pa= parseInt(getStyle(obj,attr));
      }
      var speed=(json[attr]-pa)/8;
      speed=(speed>0)?Math.ceil(speed):Math.floor(speed);
      if(json[attr]!=pa){
          flag=false;
        }
        if(attr=="opacity"){
              obj.alpha+=speed;
              obj.style.filter="alpha(opacity="+obj.alpha+")";
                obj.style[attr]=(obj.alpha)/100;
            }else{
              obj.style[attr]=pa+speed+"px";
            }
    }
    if(flag){
      clearInterval(obj.timer);
      if(fn){
        fn();
      }
    }          
     },30);
  }function getStyle(obj,attr){
  if(obj.currentStyle){
    return obj.currentStyle[attr];
  }else {
    return getComputedStyle(obj,false)[attr];
  }
}

对于链式运动,首先move()函数本身多传入一个函数参数,在move()函数在在处理好函数体的变化后,假如函数参数有值传入,则要执行后面的函数体,假如后面的参数还有函数参数,则可以继续执行下去,这样就形成了一条执行链。我上面这个列子还有一些问题,当你鼠标移动过快,会产生闪烁。具体学习视频参考慕课网JS动画效果.

    原文作者:上帝何解
    原文地址: https://segmentfault.com/a/1190000004905907
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞