JS完美运动框架详解——原理分析及demo

来源:互联网 发布:磐石软件 编辑:程序博客网 时间:2024/05/24 07:44

http://blog.csdn.net/u011175410/article/details/50351667


1.运动原理

Js运动,本质来说,就是让 web 上 DOM 元素动起来。而想要 DOM 动起来,改变其自身的位置属性,比如高宽,左边距,上边距,透明度等。还有一个很重要的前提是,运动的物体必须是绝对定位。

[javascript] view plain copy
  1. window.onload = function(){    
  2.     var oBtn = document.getElementById('btn');    
  3.     oBtn.onclick = function(){    
  4.         var oDiv = document.getElementById('div1');    
  5.         //设置定时器    
  6.         setInterval(function(){    
  7.             //改变物体位置    
  8.             oDiv.style.left = oDiv.offsetLeft + 10 + 'px';    
  9.         },30)    
  10.                                                                                                                                                                                                                                                                         
  11.     }    
  12. }  
上述代码,点击btn之后,就能是物体向左运动。可是会一直向右动,不会停止。因此需要创立一个停止的条件。在条件符合的情况下,清楚定时器。其中对于目标点的判断,尤为重要。

[javascript] view plain copy
  1. window.onload = function(){    
  2.     var oBtn = document.getElementById('btn');    
  3.     oBtn.onclick = function(){    
  4.         var oDiv = document.getElementById('div1');    
  5.         //设置定时器    
  6.         var timer = setInterval(function(){    
  7.             //判断停止条件    
  8.             if(oDiv.offsetLeft > 300){    
  9.                 clearInterval(timer);    
  10.             }else{    
  11.                 //改变物体位置    
  12.                 oDiv.style.left = oDiv.offsetLeft + 10 + 'px';    
  13.                 document.title = oDiv.offsetLeft;    
  14.             }    
  15.         },30);                                                                                                                     
  16.     }    
  17. }  
上述代码中,但物体的位置大于300的时候,将停止运动。但是上述代码还有个问题,就是连续点击按钮,物体会运动越来越快。因为每点击一次,就开了一个定时器,累加的定时器。造成运动混乱。

2,运动框架 (滑入滑出,淡入淡出)

[javascript] view plain copy
  1. window.onload = function(){    
  2.     var oBtn = document.getElementById('btn');    
  3.     oBtn.onclick = function(){    
  4.         startMove();    
  5.     }    
  6. }    
  7. var timer = null;    
  8. function startMove(){    
  9.     var oDiv = document.getElementById('div1');    
  10.     clearInterval(timer);    
  11.     //设置定时器    
  12.     timer = setInterval(function(){    
  13.         //判断停止条件    
  14.         if(oDiv.offsetLeft > 300){    
  15.             clearInterval(timer);    
  16.         }else{    
  17.             //改变物体位置    
  18.             oDiv.style.left = oDiv.offsetLeft + 10 + 'px';    
  19.             document.title = oDiv.offsetLeft;    
  20.         }    
  21.     },30);    
  22. }  
此外,在改变物体位置的时候,那个 “10”则是更改的数量,其实也就是速度。如果更改速度,运动的快慢就能确定。因此,运动框架的原理,基本步骤为:

1.先清除定时器

2.开启定时器,计算速度

3.判断停止条件,执行运动

[javascript] view plain copy
  1. var timer = null;    
  2. function startMove(){    
  3.     var oDiv = document.getElementById('div1');    
  4.     clearInterval(timer);    
  5.         //计算速度    
  6.     var iSpeed = 10;    
  7.     //设置定时器    
  8.     timer = setInterval(function(){    
  9.         //判断停止条件    
  10.         if(oDiv.offsetLeft > 300){    
  11.             clearInterval(timer);    
  12.         }else{    
  13.             //改变物体位置    
  14.             oDiv.style.left = oDiv.offsetLeft + iSpeed + 'px';    
  15.             document.title = oDiv.offsetLeft;    
  16.         }    
  17.     },30);    
  18. }  
对于停止条件,写死在里面了,所以需分离出参数。下面是一个分享到的例子。主要是根据目标判断速度的正负。从而在鼠标滑入画出时候进行运动/恢复的效果。

[html] view plain copy
  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title>JS运动——分享到</title>  
  6.     <style>  
  7.     *{padding: 0; margin: 0;}  
  8.     #div1{ width: 150px; height: 200px; background: #ccc; position: absolute; left: -150px;}  
  9.     #div1 span{ width: 20px; height: 60px; line-height: 20px; background: #8E91FF; color: #fff; position: absolute; top: 70px; right: -20px;}  
  10.     </style>  
  11.     <script>  
  12.     // 方法一:传一个参数(iTarget)  
  13.     /*window.onload = function(){  
  14.         var oDiv = document.getElementById('div1');  
  15.         var timer = null;  
  16.   
  17.         oDiv.onmouseover = function(){  
  18.             startMove(0);  
  19.         };  
  20.   
  21.         oDiv.onmouseout = function(){  
  22.             startMove(-150);  
  23.         };  
  24.   
  25.         function startMove(iTarget){  
  26.             var oDiv = document.getElementById('div1');  
  27.               
  28.             clearInterval(timer);  
  29.   
  30.             timer = setInterval(function(){  
  31.                 var speed = 0;  
  32.                   
  33.                 oDiv.offsetLeft > iTarget ? speed = -10 : speed = 10;  
  34.   
  35.                 if(oDiv.offsetLeft == iTarget){  
  36.                     clearInterval(timer);  
  37.                 }else{  
  38.                     oDiv.style.left = oDiv.offsetLeft + speed + 'px';  
  39.                 }  
  40.             },30);  
  41.         };  
  42.     };*/  
  43.   
  44.     // 方法二:传两个参数(speed,iTarget)  
  45.     window.onload = function(){  
  46.         var oDiv = document.getElementById('div1');  
  47.         var timer = null;  
  48.   
  49.         oDiv.onmouseover = function(){  
  50.             startMove(10,0);  
  51.         };  
  52.   
  53.         oDiv.onmouseout = function(){  
  54.             startMove(-10,-150);  
  55.         };  
  56.   
  57.         function startMove(speed,iTarget){  
  58.             var oDiv = document.getElementById('div1');  
  59.             clearInterval(timer);  
  60.             timer = setInterval(function(){  
  61.                 // 判断oDiv距离左边的距离是否等于目标点  
  62.                 if(oDiv.offsetLeft == iTarget){  
  63.                     clearInterval(timer);  
  64.                 }else{  
  65.                     oDiv.style.left = oDiv.offsetLeft + speed + 'px';  
  66.                 }  
  67.             },30);  
  68.         };  
  69.     };  
  70.     </script>  
  71. </head>  
  72. <body>  
  73.     <div id="div1"><span>分享到</span></div>  
  74. </body>  
  75. </html>  
另外一个小例子,淡入淡出,即改变物体的透明度,由于没有像原生的位置属性那样的offsetLset. 需要一个变量来保存透明度的值,用来和速度加减,最后付给元素的透明度样式。从而实现淡入淡出效果。

[html] view plain copy
  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title>JS运动——淡入淡出</title>  
  6.     <style>  
  7.     #div1{ width: 100px; height: 100px; background: green; position: absolute; filter:alpha(opacity:30); opacity: .3;}  
  8.     </style>  
  9.     <script>  
  10.     /*window.onload = function(){  
  11.         var oDiv = document.getElementById('div1');  
  12.         var timer = null;  
  13.         var alpha = 30;  
  14.   
  15.         oDiv.onmouseover = function(){  
  16.             startMove(100);  
  17.         };  
  18.   
  19.         oDiv.onmouseout = function(){  
  20.             startMove(30);  
  21.         };  
  22.   
  23.         function startMove(iTarget){  
  24.             var oDiv = document.getElementById('div1');  
  25.             clearInterval(timer);  
  26.             timer = setInterval(function(){  
  27.                 var speed = 0;  
  28.                 if(alpha < iTarget){  
  29.                     speed = 10;  
  30.                 }else{  
  31.                     speed = -10;  
  32.                 }  
  33.                 if(alpha == iTarget){  
  34.                     clearInterval(timer);  
  35.                 }else{  
  36.                     alpha += speed;  
  37.                     oDiv.style.filter = 'alpha(opacity:' + alpha +')';  
  38.                     oDiv.style.opacity = alpha/100;  
  39.                 }  
  40.             },30);  
  41.         };  
  42.     };*/  
  43.   
  44.     window.onload = function(){  
  45.         var oDiv = document.getElementById('div1');  
  46.         var timer = null;  
  47.         var alpha = 30;  
  48.   
  49.         oDiv.onmouseover = function(){  
  50.             startMove(10,100);  
  51.         };  
  52.   
  53.         oDiv.onmouseout = function(){  
  54.             startMove(-10,30);  
  55.         };  
  56.   
  57.         function startMove(speed,iTarget){  
  58.             var oDiv = document.getElementById('div1');  
  59.             clearInterval(timer);  
  60.             timer = setInterval(function(){  
  61.                 if(alpha == iTarget){  
  62.                     clearInterval(timer);  
  63.                 }else{  
  64.                     alpha += speed;  
  65.                     oDiv.style.filter = 'alpha(opacity:' + alpha +')';  
  66.                     oDiv.style.opacity = alpha/100;  
  67.                 }  
  68.             },30);  
  69.         }  
  70.     };  
  71.     </script>  
  72. </head>  
  73. <body>  
  74.     <div id="div1"></div>  
  75. </body>  
  76. </html>  
匀速运动:

匀速运动的停止条件:距离足够近

[html] view plain copy
  1. <!DOCTYPE HTML>  
  2. <html>  
  3. <head>  
  4. <meta charset="utf-8">  
  5. <title>匀速运动</title>  
  6. <style>  
  7. #div1 {width:100px; height:100px; background:red; position:absolute; left:600px; top:50px;}  
  8. #div2 {width:1px; height:300px; position:absolute; left:300px; top:0; background:black;}  
  9. #div3 {width:1px; height:300px; position:absolute; left:100px; top:0; background:black;}  
  10. </style>  
  11. <script>  
  12. /*  
  13.     匀速运动的停止条件  
  14.     距离足够近  
  15. */  
  16. /*var timer=null;  
  17.   
  18. function startMove(iTarget)  
  19. {  
  20.     var oDiv=document.getElementById('div1');  
  21.       
  22.     clearInterval(timer);  
  23.     timer=setInterval(function (){  
  24.         var speed=0;  
  25.           
  26.         if(oDiv.offsetLeft<iTarget)  
  27.         {  
  28.             speed=7;  
  29.         }  
  30.         else  
  31.         {  
  32.             speed=-7;  
  33.         }  
  34.           
  35.         if(Math.abs(iTarget-oDiv.offsetLeft)<=7)  
  36.         {  
  37.             clearInterval(timer);  
  38.               
  39.             oDiv.style.left=iTarget+'px';  
  40.         }  
  41.         else  
  42.         {  
  43.             oDiv.style.left=oDiv.offsetLeft+speed+'px';  
  44.         }  
  45.     }, 30);  
  46. }*/  
  47. window.onload = function(){  
  48.     var oBtn1 = document.getElementById('btn1');  
  49.     var oBtn2 = document.getElementById('btn2');  
  50.     var oDiv = document.getElementById('div1');  
  51.     var timer = null;  
  52.   
  53.     oBtn1.onclick = function(){  
  54.         startMove(100);  
  55.     };  
  56.   
  57.     oBtn2.onclick = function(){  
  58.         startMove(300);  
  59.     };  
  60.   
  61.     function startMove(iTarget){  
  62.         var oDiv = document.getElementById('div1');  
  63.         clearInterval(timer);  
  64.         timer = setInterval(function(){  
  65.             var speed = 0;  
  66.             if(oDiv.offsetLeft < iTarget ){  
  67.                 speed = 7;  
  68.             }else{  
  69.                 speed = -7;  
  70.             }  
  71.             if(Math.abs(iTarget - oDiv.offsetLeft)<=7){  
  72.                 clearInterval(timer);  
  73.                 oDiv.style.left = iTarget + 'px';  
  74.             }else{  
  75.                 oDiv.style.left = oDiv.offsetLeft + speed + 'px';  
  76.             }  
  77.         },30);  
  78.     };  
  79. };  
  80. </script>  
  81. </head>  
  82.   
  83. <body>  
  84. <!-- <input type="button" value="到100" onclick="startMove(100)" />  
  85. <input type="button" value="到300" onclick="startMove(300)" /> -->  
  86. <input id="btn1" type="button" value="运动到100" />  
  87. <input id="btn2" type="button" value="运动到300" />  
  88. <div id="div1"></div>  
  89. <div id="div2"></div>  
  90. <div id="div3"></div>  
  91. </body>  
  92. </html>  
缓冲运动

缓冲运动原理就是,改变速度的值。每次累加的速度值变小,就是会是整个物体看起来越来越慢,以至于最后停掉。

[javascript] view plain copy
  1. window.onload = function(){    
  2.     var btn = document.getElementsByTagName('input')[0];    
  3.     btn.onclick = function(){    
  4.         startMove(300);    
  5.     }    
  6. }    
  7. var timer = null;    
  8. function startMove(iTarget){    
  9.     var oDiv = document.getElementById('div1');    
  10.     clearInterval(timer);    
  11.     timer = setInterval(function(){    
  12.         //求出带有变化的速度     
  13.         var iSpeed = (iTarget - oDiv.offsetLeft) / 8;    
  14.         if(oDiv.offsetLeft == iTarget){    
  15.             clearInterval(timer);    
  16.         }else{    
  17.             oDiv.style.left = oDiv.offsetLeft + iSpeed + 'px';    
  18.         }    
  19.         document.title = oDiv.offsetLeft + '...' + iSpeed;    
  20.     },30);    
  21. }  
上述方法可以得到缓冲运动,但是实际运行效果,物体并没有在 300的位置停掉,而是在 293的位置就停掉了。究其原因。因为当物体的速度小于1 的时候。物体位置为293。此时计算的速度是 0.875.通过 oDiv.style.left = oDiv.offsetLeft + iSpeed + 'px'; 物体的位置为 293.875.可是计算机不能识别小数,将小数省略了。此时的 位置offsetLeft仍然是 293.再计算一次,还是同样的结果。定时器没有关掉,但是物体的位置却再也无法改变,故停留在了 293的位置。解决方案,就是将速度进行向上取整。但是,像上述运动,速度是正的,可是,当速度是负的时候,就同样会有相同的结果,因此需要在速度为负的时候,向下取整。
[javascript] view plain copy
  1. function startMove(iTarget){    
  2.     var oDiv = document.getElementById('div1');    
  3.     clearInterval(timer);    
  4.     timer = setInterval(function(){    
  5.         var iSpeed = (iTarget - oDiv.offsetLeft) / 8;    
  6.         //对正的速度向上取整,负的速度向下取整    
  7.         iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);    
  8.         if(oDiv.offsetLeft == iTarget){    
  9.             clearInterval(timer);    
  10.         }else{    
  11.             oDiv.style.left = oDiv.offsetLeft + iSpeed + 'px';    
  12.         }    
  13.         document.title = oDiv.offsetLeft + '...' + iSpeed;    
  14.     },30);    
  15. }  

1、当前值离目标值越近,速度越慢

     当前值离目标值越远,速度越快

     speed = (目标值-当前值)/10

2、与目标点相差一点,需要进行判断

  目标值>当前值,需要对速度向上取整,即speed = Math.ceil(speed)

  目标值<当前值,需要对速度向下取整,即speed = Math.floor(speed)

3、如果当前值=目标值,清除动画

完整缓冲运动demo

[html] view plain copy
  1. <!DOCTYPE HTML>  
  2. <html>  
  3. <head>  
  4. <meta charset="utf-8">  
  5. <title>缓冲运动</title>  
  6. <style>  
  7. #div1 {width:100px; height:100px; background:red; position:absolute; left:600px; top:50px;}  
  8. #div2 {width:1px; height:300px; background:black; position:absolute; left:300px; top:0;}  
  9. </style>  
  10. <script>  
  11. window.onload = function(){  
  12.     var oBtn = document.getElementById('btn1');  
  13.     var oDiv = document.getElementById('div1');  
  14.     var timer = null;  
  15.   
  16.     oBtn.onclick = function(){  
  17.         startMove(300);  
  18.     };  
  19.   
  20.     function startMove(iTarget){  
  21.         var oDiv = document.getElementById('div1');  
  22.         clearInterval(timer);  
  23.         timer = setInterval(function(){  
  24.             var speed = (iTarget - oDiv.offsetLeft)/10;  
  25.             // 但凡用到缓冲运动,一定要用到向上/向下取整!  
  26.             speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);  
  27.             oDiv.style.left = oDiv.offsetLeft + speed + 'px';  
  28.             document.title=oDiv.offsetLeft+','+speed;     
  29.         },30);  
  30.     }  
  31.   
  32. };  
  33. </script>  
  34. </head>  
  35.   
  36. <body>  
  37. <input id="btn1" type="button" value="缓冲运动到300" />  
  38. <div id="div1"></div>  
  39. <div id="div2"></div>  
  40. </body>  
  41. </html>  
多物体运动
下一步,就是处理多物体运动,运动函数里面每次都要选取一个元素加事件。如果需要对多个物体进行同样的运动, 需要将运动对象作为参数传进来。

[javascript] view plain copy
  1. window.onload = function(){    
  2.     var aDiv = document.getElementsByTagName('div');    
  3.     for(var i=0;i<aDiv.length;i++){    
  4.         aDiv[i].onmouseover = function(){    
  5.             startMove(this,300);    
  6.         }    
  7.         aDiv[i].onmouseout = function(){    
  8.             startMove(this,100);    
  9.         }    
  10.     }    
  11. }    
  12. var timer = null;    
  13. function startMove(obj,iTarget){    
  14.     clearInterval(timer);    
  15.     timer = setInterval(function(){    
  16.         var iSpeed = (iTarget - obj.offsetWidth) / 8;    
  17.         iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);    
  18.         if(obj.offsetWidth == iTarget){    
  19.             clearInterval(timer);    
  20.         }else{    
  21.             obj.style.width = obj.offsetWidth + iSpeed + 'px';    
  22.         }    
  23.                                                                                                                                                            
  24.     },30)    
  25. }  
通过循环物体,将物体的 this传给运动函数,使得多物体可以运动。但是这样有一个弊端,即当滑入第一个运动的时候,开启了定时器。如果此时,滑入另外一个物体,将会清理上一个定时器。这就造成了,上一次运动,很有可能还没完成结束,定时器就没关闭了。解决的方法,每个运动的物体,都能开了一个属于自己的定时器。因此,把定时器当成物体的属性。清理的时候也就是清理自己的定时器。
[javascript] view plain copy
  1. window.onload = function(){    
  2.     var aDiv = document.getElementsByTagName('div');    
  3.     for(var i=0;i<aDiv.length;i++){    
  4.         aDiv[i].onmouseover = function(){    
  5.             startMove(this,300);    
  6.         }    
  7.         aDiv[i].onmouseout = function(){    
  8.             startMove(this,100);    
  9.         }    
  10.     }    
  11. }    
  12. function startMove(obj,iTarget){    
  13.     //将定时器,变成物体的属性,类似给物体添加索引    
  14.     clearInterval(obj.timer);    
  15.     obj.timer = setInterval(function(){    
  16.         var iSpeed = (iTarget - obj.offsetWidth) / 8;    
  17.         iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);    
  18.         if(obj.offsetWidth == iTarget){    
  19.             clearInterval(obj.timer);    
  20.         }else{    
  21.             obj.style.width = obj.offsetWidth + iSpeed + 'px';    
  22.         }    
  23.                                                                                                                                                
  24.     },30)    
  25. }  
多物体运动完整demo

[html] view plain copy
  1. <!DOCTYPE HTML>  
  2. <html>  
  3. <head>  
  4. <meta charset="utf-8">  
  5. <title>多物体运动——改变物体宽度</title>  
  6. <style>  
  7. div {width:100px; height:50px; background:red; margin:10px; border:10px solid black;}  
  8. </style>  
  9. <script>  
  10. window.onload = function(){  
  11.     var aDiv = document.getElementsByTagName('div');  
  12.   
  13.     for( var i = 0; i < aDiv.length; i++){  
  14.         aDiv[i].timer = null;  
  15.           
  16.         aDiv[i].onmouseover = function(){  
  17.             startMove(this,400);  
  18.         };  
  19.   
  20.         aDiv[i].onmouseout = function(){  
  21.             startMove(this,100);  
  22.         };  
  23.     }  
  24.   
  25.     function startMove(obj,iTarget){  
  26.         clearInterval(obj.timer);  
  27.         obj.timer = setInterval(function(){  
  28.             var speed = (iTarget - obj.offsetWidth)/6;  
  29.             speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);  
  30.             if( obj.offsetWidth == iTarget){  
  31.                 clearInterval(obj.timer);  
  32.             }else{  
  33.                 obj.style.width = obj.offsetWidth + speed + 'px';  
  34.             }  
  35.         },30);  
  36.     };  
  37. };  
  38. </script>  
  39. </head>  
  40.   
  41. <body>  
  42. <div></div>  
  43. <div></div>  
  44. <div></div>  
  45. </body>  
  46. </html>  
多物体的淡入淡出的时候,也有类似的问题。因为修改透明度的时候,是先用一个变量保存透明度,必须针对每个物体设立透明度值属性。

多物体运动透明度demo

[html] view plain copy
  1. <!DOCTYPE HTML>  
  2. <html>  
  3. <head>  
  4. <meta charset="utf-8">  
  5. <title>多物体运动——改变物体透明度</title>  
  6. <style>  
  7. div {width:100px; height:50px; background:red; margin:10px; border:10px solid black; filter:alpha(opacity:30); opacity: .3;}  
  8. </style>  
  9. <script>  
  10. window.onload = function(){  
  11.     var aDiv = document.getElementsByTagName('div');  
  12.   
  13.     for( var i = 0; i < aDiv.length; i++){  
  14.         aDiv[i].timer = null;  
  15.         aDiv[i].alpha = 30;   
  16.         aDiv[i].onmouseover = function(){  
  17.             startMove(this,100);  
  18.         };  
  19.   
  20.         aDiv[i].onmouseout = function(){  
  21.             startMove(this,30);  
  22.         };  
  23.     }  
  24.   
  25.     function startMove(obj,iTarget){  
  26.         clearInterval(obj.timer);  
  27.         obj.timer = setInterval(function(){  
  28.             var speed = (iTarget - obj.alpha)/6;  
  29.             speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);  
  30.             if( obj.alpha == iTarget){  
  31.                 clearInterval(obj.timer);  
  32.             }else{  
  33.                 obj.alpha += speed;    
  34.                 obj.style.filter = 'alpha(opacity:'+obj.alpha+')';    
  35.                 obj.style.opacity = obj.alpha / 100;    
  36.             }  
  37.         },30);  
  38.     };  
  39. };  
  40. </script>  
  41. </head>  
  42.   
  43. <body>  
  44. <div></div>  
  45. <div></div>  
  46. <div></div>  
  47. </body>  
  48. </html>  
位置属性的bug

offsetWidth 或者 offsetHeight 等位置属性,一旦给他们加上 border。则会有诡异的现象出现。

[javascript] view plain copy
  1. window.onload = function(){    
  2.         var oDiv = document.getElementById('div1');    
  3.         setInterval(function(){    
  4.             oDiv.style.width = oDiv.offsetWidth - 1 + "px";    
  5.         },30)    
  6.     }    
例如 oDiv.style.width = oDiv.offsetWidth - 1 + 'px'; 如果给 oDiv 的width 为一百,border 为 1.则这个物体的 width是100px;offsetWidth 为102px;带入公式之后,即减一之后。100 = 102 - 1 ,反而等于101;即 物体本来要减小,事实却增大了。解决的方案就是,加减的时候,必须使用物体的内联样式。但是 火狐 和 IE 又有兼容模式。解决方案如下:

[javascript] view plain copy
  1. window.onload = function(){    
  2.         var oDiv = document.getElementById('div1');    
  3.         setInterval(function(){    
  4.                                                                                                                      
  5.             oDiv.style.width = parseInt(getStyle(oDiv,'width')) - 1 + 'px';    
  6.                                                                                                           
  7.         },30)    
  8.     }    
  9.     function getStyle(obj,attr){    
  10.         if(obj.currentStyle){    
  11.             return obj.currentStyle[attr];    
  12.         }else{    
  13.             return getComputedStyle(obj,false)[attr];    
  14.         }    
  15.     }  
其中,getStyle函数,传入一个元素对象,和其 css 属性,获取的是元素的样式,即 witdh 100px;因此需要parseInt转换
任意值运动demo

[html] view plain copy
  1. <!DOCTYPE HTML>  
  2. <html>  
  3. <head>  
  4. <meta charset="utf-8">  
  5. <title>JS任意值运动</title>  
  6. <style>  
  7. div {width:100px; height:100px; margin:20px; float:left; background: #ccc; border:10px solid black; font-size:14px;}  
  8. </style>  
  9. <script>  
  10. window.onload=function ()  
  11. {  
  12.     var oDiv1=document.getElementById('div1');  
  13.     oDiv1.onmouseover=function (){startMove(this, 'height', 400);};  
  14.     oDiv1.onmouseout=function (){startMove(this, 'height', 200);};  
  15.       
  16.     var oDiv2=document.getElementById('div2');  
  17.       
  18.     oDiv2.onmouseover=function (){startMove(this, 'width', 400);};  
  19.     oDiv2.onmouseout=function (){startMove(this, 'width', 200);};  
  20.       
  21.     var oDiv3=document.getElementById('div3');  
  22.     oDiv3.onmouseover=function (){startMove(this, 'fontSize', 30);};  
  23.     oDiv3.onmouseout=function (){startMove(this, 'fontSize', 14);};  
  24.       
  25.     var oDiv4=document.getElementById('div4');  
  26.     oDiv4.onmouseover=function (){startMove(this, 'borderWidth', 100);};  
  27.     oDiv4.onmouseout=function (){startMove(this, 'borderWidth', 10);};  
  28. };  
  29.   
  30. function getStyle(obj, name)  
  31. {  
  32.     return obj.currentStyle ? obj.currentStyle[name] : getComputedStyle( obj ,false )[name];  
  33. }  
  34.   
  35. function startMove(obj, attr, iTarget)  
  36. {  
  37.     clearInterval(obj.timer);  
  38.     obj.timer=setInterval(function (){  
  39.         var cur=parseInt(getStyle(obj, attr));  
  40.           
  41.         var speed=(iTarget-cur)/6;  
  42.         speed=speed>0?Math.ceil(speed):Math.floor(speed);  
  43.           
  44.         if(cur==iTarget)  
  45.         {  
  46.             clearInterval(obj.timer);  
  47.         }  
  48.         else  
  49.         {  
  50.             obj.style[attr]=cur+speed+'px';  
  51.         }  
  52.     }, 30);  
  53. }  
  54. </script>  
  55. </head>  
  56.   
  57. <body>  
  58. <div id="div1">变高</div>  
  59. <div id="div2">变宽</div>  
  60. <div id="div3">safasfasd</div>  
  61. <div id="div4"></div>  
  62. </body>  
  63. </html>  

任意值完美版demo

上述版本,还不能处理透明度的任意值,因此需要增加额外的兼容hack。

[html] view plain copy
  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title>JS任意值运动完美版</title>  
  6.     <style>  
  7.     #div1{ width: 100px; height: 100px; background: green; position: absolute; filter:alpha(opacity:30); opacity: .3;}  
  8.     #div2{ width: 100px; height: 100px; background: green; position: absolute; top: 120px;}  
  9.     </style>  
  10.     <script>  
  11.     window.onload = function(){  
  12.         var aDiv = document.getElementsByTagName('div');  
  13.         aDiv[0].onmouseover = function(){  
  14.             startMove(this,'opacity',100);  
  15.         }  
  16.         aDiv[0].onmouseout = function(){  
  17.             startMove(this,'opacity',30);  
  18.         }  
  19.   
  20.         aDiv[1].onmouseover = function(){  
  21.             startMove(this,'width','200');  
  22.         }  
  23.         aDiv[1].onmouseout = function(){  
  24.             startMove(this,'width','100');  
  25.         }  
  26.     }  
  27.   
  28.     function getStyle(obj, attr){  
  29.         if(obj.currentStyle)    {  
  30.             return obj.currentStyle[attr];  
  31.         }else{  
  32.             return getComputedStyle(obj, false)[attr];  
  33.         }  
  34.     }  
  35.     function startMove(obj,attr,iTarget){  
  36.         clearInterval(obj.timer);  
  37.         obj.timer = setInterval(function(){  
  38.             var iCur = 0;  
  39.             if(attr == 'opacity'){  
  40.                 iCur = parseInt(parseFloat(getStyle(obj, attr))*100);  
  41.             }else{  
  42.                 iCur = parseInt(getStyle(obj,attr));  
  43.             }  
  44.             var iSpeed = (iTarget - iCur) / 8;  
  45.             iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);  
  46.             if(iCur == iTarget){  
  47.                 clearInterval(obj.timer);  
  48.             }else{  
  49.                 if(attr=='opacity'){  
  50.                     iCur += iSpeed  
  51.                     obj.style.filter='alpha(opacity:' + iCur + ')';  
  52.                     obj.style.opacity=iCur / 100;  
  53.                 }  
  54.                 else{  
  55.                     obj.style[attr]=iCur+iSpeed+'px';  
  56.                 }  
  57.                 document.title = obj.style[attr];  
  58.             }  
  59.                                                                                       
  60.         },30)  
  61.     }  
  62.     </script>  
  63. </head>  
  64. <body>  
  65.     <div id="div1"></div>  
  66.     <div id="div2"></div>  
  67. </body>  
  68. </html>  

链式运动demo

我们的运动框架到目前为止,基本功能都能实现了。现在拓展。所谓链式运动,即运动接着运动。当运动停止的时候,如果回调一个函数。回调一个运动函数,就能出现这样的效果。因此传入一个函数作为回调函数。

[html] view plain copy
  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title>JS运动——链式运动</title>  
  6.     <style>  
  7.     #div1{ width: 100px; height: 100px; background: green; position: absolute; filter:alpha(opacity:30); opacity: .3;}  
  8.     </style>  
  9.     <script>  
  10.     window.onload = function(){  
  11.         var oDiv = document.getElementById('div1');  
  12.         oDiv.onclick = function(){  
  13.             startMove(this,'width',300,function(){  
  14.                 startMove(oDiv,'height',300,function(){  
  15.                     startMove(oDiv,'opacity',100)  
  16.                 })  
  17.             })  
  18.         }  
  19.     }  
  20.     function getStyle(obj,attr){  
  21.         if(obj.currentStyle){  
  22.             return obj.currentStyleattr[attr];  
  23.         }else{  
  24.             return getComputedStyle(obj, false)[attr];  
  25.         }  
  26.     }  
  27.                                                                           
  28.     function startMove(obj,attr,iTarget,fn){  
  29.         clearInterval(obj.timer);  
  30.         obj.timer = setInterval(function(){  
  31.             var iCur = 0;  
  32.             if(attr == 'opacity'){  
  33.                 iCur = parseInt(parseFloat(getStyle(obj, attr))*100);  
  34.             }else{  
  35.                 iCur = parseInt(getStyle(obj,attr));  
  36.             }  
  37.             var iSpeed = (iTarget - iCur) / 8;  
  38.             iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);  
  39.             if(iCur == iTarget){  
  40.                 clearInterval(obj.timer);  
  41.                 //回调函数  
  42.                 if(fn) fn();  
  43.             }else{  
  44.                 if(attr=='opacity'){  
  45.                     iCur += iSpeed  
  46.                     obj.style.filter='alpha(opacity:' + iCur + ')';  
  47.                     obj.style.opacity=iCur / 100;  
  48.                 }  
  49.                 else{  
  50.                     obj.style[attr]=iCur+iSpeed+'px';  
  51.                 }  
  52.                 document.title = obj.style[attr];  
  53.             }  
  54.                                                                             
  55.         },30)  
  56.     }  
  57.     </script>  
  58. </head>  
  59. <body>  
  60.     <h4>点击下面的方块试试链式运动的效果</h4>  
  61.     <div id="div1"></div>  
  62. </body>  
  63. </html>  

同时运动demo

目前为止,我们的运动框架还有个小缺点,就是不能同时该两个属性进行运动,比如同时更改宽和高。这个要求传入的属性是不同的几个值。则考虑传入一个 json用来保存需要更改的属性。

[html] view plain copy
  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title>JS运动——同时运动(有bug)</title>  
  6.     <style>  
  7.     #div1{ width: 100px; height: 100px; background: green; position: absolute;}  
  8.     </style>  
  9.     <script>  
  10.     window.onload = function(){  
  11.         var oDiv = document.getElementById('div1');  
  12.         oDiv.onclick = function(){  
  13.             startMove(this,{'width':200,'height':500});  
  14.         }  
  15.     }  
  16.     function getStyle(obj, attr){  
  17.         if(obj.currentStyle)    {  
  18.             return obj.currentStyle[attr];  
  19.         }else{  
  20.             return getComputedStyle(obj, false)[attr];  
  21.         }  
  22.     }  
  23.     function startMove(obj,json,fn){  
  24.         clearInterval(obj.timer);  
  25.         obj.timer = setInterval(function(){  
  26.          // 循环json   
  27.          for(var attr in json){        
  28.                 var iCur = 0;  
  29.                 if(attr == 'opacity'){  
  30.                     iCur = parseInt(parseFloat(getStyle(obj, attr))*100);  
  31.                 }else{  
  32.                     iCur = parseInt(getStyle(obj,attr));  
  33.                 }  
  34.                 var iSpeed = (json[attr] - iCur) / 8;  
  35.                 iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);  
  36.                 if(iCur == json[attr]){  
  37.                     clearInterval(obj.timer);  
  38.                     if(fn) fn();  
  39.                 }else{  
  40.                     if(attr=='opacity'){  
  41.                         iCur += iSpeed  
  42.                         obj.style.filter='alpha(opacity:' + iCur + ')';  
  43.                         obj.style.opacity=iCur / 100;  
  44.                     }  
  45.                     else{  
  46.                         obj.style[attr]=iCur+iSpeed+'px';  
  47.                     }  
  48.                     document.title = obj.style[attr];  
  49.                 }  
  50.             }  
  51.         },30)  
  52.     }      
  53.     </script>  
  54. </head>  
  55. <body>  
  56.     <h4>点击下面的方块试试同时运动效果</h4>  
  57.     <div id="div1"></div>  
  58. </body>  
  59. </html>  
上述代码,可以解决了同时运动的问题。但是还是有一个bug。比如,同时运动的某个属性,如果变化很小,马上就停止了,即关掉了定时器。那么会造成其他属性的变化也停止。因为这些属性都共用了一个定时器。因此需要判断,假设有三个人要来,然后一起去爬山。三个人有的先来,有的后来,只要三个人都到齐了,才出发。也就是只有三个属性都到了目标值,才关定时器。一开始,设立一个检查量,为真。假设所有人都到了,然后循环,只有有一个人没有到,检查就为假。直到所有的都到了,检测为真。则停止定时器。

同时运动完美版

[html] view plain copy
  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title>JS运动——同时运动完美版</title>  
  6.     <style>  
  7.     #div1{ width: 100px; height: 100px; background: green; position: absolute; filter:alpha(opacity:30); opacity: .3;}  
  8.     </style>  
  9.     <script>  
  10.     window.onload = function(){  
  11.         var oDiv = document.getElementById('div1');  
  12.         oDiv.onclick = function(){  
  13.             startMove(this,{'width':200,'height':200,'opacity':100});  
  14.         }  
  15.     }  
  16.     function getStyle(obj, attr){  
  17.         if(obj.currentStyle)    {  
  18.             return obj.currentStyle[attr];  
  19.         }else{  
  20.             return getComputedStyle(obj, false)[attr];  
  21.         }  
  22.     }  
  23.     function startMove(obj,json,fn){  
  24.         clearInterval(obj.timer);  
  25.         obj.timer = setInterval(function(){  
  26.             var bStop = true;  
  27.             for(var attr in json){    
  28.                 //取当前值    
  29.                 var iCur = 0;  
  30.                 if(attr == 'opacity'){  
  31.                     iCur = parseInt(parseFloat(getStyle(obj, attr))*100);  
  32.                 }else{  
  33.                     iCur = parseInt(getStyle(obj,attr));  
  34.                 }  
  35.                 //计算速度  
  36.                 var iSpeed = (json[attr] - iCur) / 8;  
  37.                 iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);  
  38.                 //检测停止  
  39.                 if(iCur != json[attr]){  
  40.                     bStop = false;  
  41.                 }     
  42.                 if(attr=='opacity'){  
  43.                     iCur += iSpeed  
  44.                     obj.style.filter='alpha(opacity:' + iCur + ')';  
  45.                     obj.style.opacity=iCur / 100;  
  46.                 }  
  47.                 else{  
  48.                     obj.style[attr]=iCur+iSpeed+'px';  
  49.                 }  
  50.             }  
  51.             if(bStop){  
  52.                 clearInterval(obj.timer);  
  53.                 if(fn) fn();  
  54.             }  
  55.         },30)  
  56.     }  
  57.     </script>  
  58. </head>  
  59. <body>  
  60.     <h4>点击下面的方块试试同时运动效果</h4>  
  61.     <div id="div1"></div>  
  62. </body>  
  63. </html>  
再循环外定义一个 标志变量 bStop = true。用来表示所有属性到达目标值。等循环结束了,如果这个值是真的,则停止定时器。因为,每次运行定时器,都会初始化这个值。循环的过程中,只要有一个没有到,bStop就被设定为 false。如果某个到了,此时 iCur != json[attr],表示速度为0 后面执行的结果,也不会有变化。只有所有的都达到目标值。循环则不再改变 bStop的值。此时,只要下一次运行定时器。就是初始化 bStop为真。而循环因为都到了,所以速度为0 也就再也没有变化。循环结束,sBstop还是真,表示所有都到了。因此此时结束定时器。

最后附上完美运动框架,封装成 move.js 就可以调用了。

[javascript] view plain copy
  1. /**  
  2.    * getStyle 获取样式  
  3.    * startMove 运动主程序  
  4. */    
  5.                      
  6.   function getStyle(obj, attr){    
  7.       if(obj.currentStyle)    {    
  8.           return obj.currentStyle[attr]; //for ie   
  9.      }else{    
  10.          return getComputedStyle(obj, false)[attr];  // for ff  
  11.      }    
  12.  }    
  13.  function Move(obj,json,fn){    
  14.      //停止上一次定时器    
  15.      clearInterval(obj.timer); //关闭前一个定时器,解决对同个对象同时调用多个Move()时,定时器叠加问题。使用obj.timer给每个调用Move()的对象赋予各自的定时器,防止多个对象同时调用Move()时,同用一个定时器,而导致相关干扰问题。   
  16.      //保存每一个物体运动的定时器    
  17.      obj.timer = setInterval(function(){    
  18.          //判断同时运动标志    
  19.          var bStop = true;    
  20.          for(var attr in json){      
  21.              //取当前值      
  22.              var iCur = 0;  //创建一个变量,用于存储 attr属性每时每刻的值  
  23.              if(attr == 'opacity'){    
  24.               //针对在FF中opacity属性值为浮点数值问题,将属性值 四舍五入、转换成浮点型。乘以100,使opacity属性值与IE统一为百分数  
  25.                  iCur = Math.round(parseFloat(getStyle(obj, attr))*100);    
  26.              }else{    
  27.                  iCur = parseInt(getStyle(obj,attr)); //将除opacity外的属性(width/fontSize/MarginLeft等)的初始值 转换为整型   
  28.              }    
  29.              //计算速度    
  30.              var iSpeed = (json[attr] - iCur) / 8;  //创建 递减的速度speed变量。实现属性值的变速改变  
  31.              iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);  //取整,解决浏览器忽略小于1px的数值 导致运动结束时,离目标值Itarget少几个像素的问题  
  32.              //检测同时到达标志    
  33.              if(iCur != json[attr]){    
  34.                  bStop = false;    
  35.              }       
  36.              //更改属性,获取动画效果    
  37.              if(attr=='opacity'){    
  38.                  iCur += iSpeed    
  39.                  obj.style.filter='alpha(opacity:' + iCur + ')';    
  40.                  obj.style.opacity=iCur / 100;    
  41.              }    
  42.              else{    
  43.                  obj.style[attr]=iCur+iSpeed+'px';    
  44.              }    
  45.          }    
  46.          //检测停止    
  47.          if(bStop){    
  48.              clearInterval(obj.timer);    
  49.              if(fn) fn();    
  50.          }    
  51.      },30)    
  52.   }  

原创粉丝点击