《js动画效果》之获取元素属性

本文详细解析了JS动画效果的实现过程,并针对一个特定案例进行了深入探讨,包括元素样式设置、事件绑定、属性获取方法封装及代码优化,旨在解决在停止运动时目标宽度未达到预期的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


js

学习资源来自慕课网《js动画效果》:http://www.imooc.com/video/3049/0。

在上一节《js动画效果》之多物体动画效果中的例子1 :

1. 网页上有一ul, ul中有三个li元素,要求鼠标移到(onmouseover) li 元素上产生动画效果——宽度值增加到300px,鼠标移出(onmouseout) li 元素产生动画效果——宽度值复原到200px.

  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <meta charset="utf-8">  
  5.         <style type="text/css">  
  6.         *{  
  7.             padding:0;  
  8.             margin:0;  
  9.         }  
  10.         <span style="color:#ff0000;">ul li{  
  11.             list-style:none;  
  12.             width:200px;  
  13.             height:100px;  
  14.             background:green;  
  15.             margin:20px;  
  16.         }</span>  
  17.         </style>  
  18.         <script type="text/javascript">  
  19.         /***  
  20.             实现多物体运动的关键点:  
  21.             1)获取到每个元素;  
  22.             2)给每个元素绑定上事件;  
  23.             3)注意使用this区分当前操作的元素;  
  24.             4)定时器不能只设一个了,应该给每个元素分配一个定时器,避免多个元素抢同一个定时器造成bug  
  25.   
  26.             记住:多物体运动不能共用同一个东西(某一参数,比如定时器)  
  27.         ***/  
  28.             window.onload = function(){  
  29.                 var liEles = document.getElementsByTagName("li");  
  30.   
  31.                 for(var i=0; i<liEles.length; i++){  
  32.   
  33.                     //给每一个li元素定义一个定时器,避免多个元素抢同一个定时器造成bug  
  34.                     liEles[i].timer = null;  
  35.                     liEles[i].onmouseover = function(){  
  36.   
  37.                         //传入this值,指定当前操作的是哪个li  
  38.                         playFun(this, 300);  
  39.                     };  
  40.                     liEles[i].onmouseout = function(){  
  41.                         playFun(this, 200);  
  42.                     };  
  43.                 }  
  44.             }  
  45.   
  46.             //var timer = null;  
  47.             function playFun(obj,itarget){  
  48.                 clearInterval(obj.timer);  
  49.                 obj.timer = setInterval(function(){  
  50.                     var speed = (itarget - obj.offsetWidth)/10;  
  51.                     speed = speed>0?Math.ceil(speed):Math.floor(speed);  
  52.                       
  53.                     if(obj.offsetWidth == itarget){  
  54.                         clearInterval(obj.timer);  
  55.                     }else{  
  56.                         obj.style.width = obj.offsetWidth + speed + "px";  
  57.                     }  
  58.                 },50);  
  59.             }  
  60.         </script>  
  61.     </head>  
  62.     <body>  
  63.         <ul>  
  64.             <li></li>  
  65.             <li></li>  
  66.             <li></li>  
  67.         </ul>  
  68.     </body>  
  69. </html>  

li 元素的样式中没有设置 border属性,下面我们重新设置li元素的样式为:

  1. ul li{  
  2.             list-style:none;  
  3.             width:200px;  
  4.             height:100px;  
  5.             background:green;  
  6.             margin:20px;  
  7.             <span style="color:#ff0000;">border:2px #ccc solid;</span>  
  8.         }  
然后在浏览器中运行代码,会发现物体在停止运动时并没有达到规定的目标值200px、300px,如下图示:

 

左边的图表示的是鼠标移入移出,物体停止运动时的width值得结果;右图是每运动一次后console.log(obj.offsetWidth )的值。通过结果可以分析得出造成bug的原因:

代码中一直采用 offsetWidth 来计算物体的宽度, 而 offsetWidth = width + padding(left + right) + border(left + right) ,下面来分析代码,当物体停止运动,console.log(obj.offsetWidth )的输出值为 240 ,对应 width 的值为236,目前定时器仍在运行中,将target 值 200 和 obj.offsetWidth的当前值 240 带入下面公式计算得出 speed = -4

var speed = (itarget - obj.offsetWidth)/10;
 speed = speed>0?Math.ceil(speed):Math.floor(speed);

再将obj.offsetWidth的值 240和speed的值 -4  带入公式

obj.style.width = obj.offsetWidth + speed + "px";

得出 width = 236;

下面进入下次定时器的运算,offsetWidth = width + border( 2+2 ) = 240, 又带入各公式计算出width的值还是 236 ,如此死循环下去。


解决方法:

法1)此法是课程中老师讲解的方法——封装一个专门获取属性值得方法,代码如下:

  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <meta charset="utf-8">  
  5.         <style type="text/css">  
  6.         *{  
  7.             padding:0;  
  8.             margin:0;  
  9.         }  
  10.         ul li{  
  11.             list-style:none;  
  12.             width:200px;  
  13.             height:100px;  
  14.             background:green;  
  15.             margin:20px;  
  16.             border:2px #ccc solid;  
  17.         }  
  18.         </style>  
  19.         <script type="text/javascript">  
  20.         /***  
  21.             实现多物体运动的关键点:  
  22.             1)获取到每个元素;  
  23.             2)给每个元素绑定上事件;  
  24.             3)注意使用this区分当前操作的元素;  
  25.             4)定时器不能只设一个了,应该给每个元素分配一个定时器,避免多个元素抢同一个定时器造成bug  
  26.   
  27.             记住:多物体运动不能共用同一个东西(某一参数,比如定时器)  
  28.         ***/  
  29.             window.onload = function(){  
  30.                 var liEles = document.getElementsByTagName("li");  
  31.   
  32.                 for(var i=0; i<liEles.length; i++){  
  33.   
  34.                     //给每一个li元素定义一个定时器,避免多个元素抢同一个定时器造成bug  
  35.                     liEles[i].timer = null;  
  36.                     liEles[i].onmouseover = function(){  
  37.   
  38.                         //传入this值,指定当前操作的是哪个li  
  39.                         playFun(this, 300);  
  40.                     };  
  41.                     liEles[i].onmouseout = function(){  
  42.                         playFun(this, 200);  
  43.                     };  
  44.                 }  
  45.             }  
  46.   
  47.             //var timer = null;  
  48.             function playFun(obj,itarget){  
  49.                 clearInterval(obj.timer);  
  50.                 obj.timer = setInterval(function(){  
  51.                     var speed = (itarget - <span style="color:#ff0000;">parseInt(getStle(obj,"width"))</span>)/10;  
  52.                     speed = speed>0?Math.ceil(speed):Math.floor(speed);  
  53.                       
  54.                     if(<span style="color:#ff0000;">parseInt(getStle(obj,"width"))</span> == itarget){  
  55.                         clearInterval(obj.timer);  
  56.                     }else{  
  57.                         //obj.style.width = obj.offsetWidth + speed + "px";  
  58.                         obj.style.width = <span style="color:#ff0000;">parseInt(getStle(obj,"width"))</span> + speed + "px";  
  59.                     }  
  60.                 },50);  
  61.             }  
  62.             //获取属性值  
  63.             function getStle(ele,attr){   
  64.                 if(ele.currentStyle){ //兼容IE浏览器  
  65.                     return ele.currentStyle[attr];  
  66.                 }else{  //兼容firefox浏览器  
  67.                     return getComputedStyle(ele,false)[attr];  
  68.                 }  
  69.             }</span>  
  70.         </script>  
  71.     </head>  
  72.     <body>  
  73.         <ul>  
  74.             <li></li>  
  75.             <li></li>  
  76.             <li></li>  
  77.         </ul>  
  78.     </body>  
  79. </html>  

法2)offsetWidth的值包含了border, 但是 offsetClient = width + padding 没有包含border的值,单单就这个例子而言,用  offsetClient 还是可以解决问题,修改部分代码如下。但是如果css中设置了padding值,就不好使了,所以,还是采用老师的方法最好,封装一个专门获取css属性值得函数,可以获取别的属性。

[javascript] view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. function playFun(obj,itarget){  
  2.                 clearInterval(obj.timer);  
  3.                 obj.timer = setInterval(function(){  
  4.                     var speed = (itarget - obj.clientWidth)/10;  
  5.                     speed = speed>0?Math.ceil(speed):Math.floor(speed);  
  6.                       
  7.                     if(obj.clientWidth == itarget){  
  8.                         clearInterval(obj.timer);  
  9.                     }else{  
  10.                         obj.style.width = obj.clientWidth + speed + "px";  
  11.                     }  
  12.                 },50);  
  13.             }  

3. 将代码封装成可以获取任意属性值(这里主要要对属性为opacity时做单独的处理),练习代码如下:

  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <meta charset="utf-8">  
  5.         <style type="text/css">  
  6.         *{  
  7.             padding:0;  
  8.             margin:0;  
  9.         }  
  10.         ul li{  
  11.             list-style:none;  
  12.             width:200px;  
  13.             height:100px;  
  14.             background:green;  
  15.             margin:20px;  
  16.             border:2px #ccc solid;  
  17.             filter:alpha(opacity:30);  
  18.             opacity:0.3;  
  19.         }  
  20.         </style>  
  21.         <script type="text/javascript">  
  22.             window.onload = function(){  
  23.                 var liEles = document.getElementsByTagName("li");  
  24.   
  25.                 for(var i=0; i<liEles.length; i++){  
  26.   
  27.                     //给每一个li元素定义一个定时器,避免多个元素抢同一个定时器造成bug  
  28.                     liEles[i].timer = null;  
  29.                     liEles[i].onmouseover = function(){  
  30.   
  31.                         //传入this值,指定当前操作的是哪个li  
  32.                         //playFun(this, 300, "width");  
  33.                         playFun(this, 100, "opacity");  
  34.                     };  
  35.                     liEles[i].onmouseout = function(){  
  36.                         playFun(this, 30, "opacity");  
  37.                     };  
  38.                 }  
  39.             }  
  40.   
  41.             function playFun(obj,itarget,attr){  
  42.                 clearInterval(obj.timer);  
  43.                 obj.timer = setInterval(function(){  
  44.                     var getValue = 0;  
  45.                     if(attr == "opacity"){  
  46.   
  47.                         //parseFloat返回小数值  
  48.                         //由于计算机存储小数有误差,采用Math.round()四舍五入得整数  
  49.                         getValue = Math.round(parseFloat(getStle(obj,attr))*100);  
  50.                     }else{  
  51.                         getValue = parseInt(getStle(obj,attr));  
  52.                     }  
  53.                       
  54.                     var speed = (itarget - getValue)/10;  
  55.                     speed = speed>0?Math.ceil(speed):Math.floor(speed);  
  56.                       
  57.                     if(getValue == itarget){  
  58.                         clearInterval(obj.timer);  
  59.                     }else{  
  60.                         //obj.style[attr],采用中括号传参  
  61.                         if(attr == "opacity"){  
  62.                             getValue += speed;  
  63.                             obj.style["filter"] = "alpha(opacity:"+ getValue +")";  
  64.                             obj.style["opacity"] = getValue/100;  
  65.                         }else{  
  66.                             obj.style[attr] = getValue + speed + "px";  
  67.                         }  
  68.                           
  69.                     }  
  70.                 },50);  
  71.             }  
  72.   
  73.             //获取属性值  
  74.             function getStle(ele,attr){   
  75.                 if(ele.currentStyle){ //兼容IE浏览器  
  76.                     return ele.currentStyle[attr];  
  77.                 }else{  //兼容firefox浏览器  
  78.                     return getComputedStyle(ele,false)[attr];  
  79.                 }  
  80.             }  
  81.         </script>  
  82.     </head>  
  83.     <body>  
  84.         <ul>  
  85.             <li></li>  
  86.             <li></li>  
  87.             <li></li>  
  88.         </ul>  
  89.     </body>  
  90. </html>  
封装时的注意点:

1)opacity的取值,getStle(obj,attr)获取的opacity返回值为小数,需要采用parseFloat(getStle(obj,attr))*100 来获取并乘以100转为整数;

2)由于计算机存储小数有误差,所以还需采用Math.round()四舍五入得整数;

3)最后赋值css时,注意浏览器兼容:

      obj.style["filter"] = "alpha(opacity:"+ getValue +")";
      obj.style["opacity"] = getValue/100;   // opacity 的值以小数表示
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值