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

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

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

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

 <!DOCTYPE html>
 <html>
 	<head>
 		<meta charset="utf-8">
 		<style type="text/css">
 		*{
 			padding:0;
 			margin:0;
 		}
 		<span style="color:#ff0000;">ul li{
 			list-style:none;
 			width:200px;
 			height:100px;
 			background:green;
 			margin:20px;
 		}</span>
 		</style>
 		<script type="text/javascript">
 		/***
 			实现多物体运动的关键点:
 			1)获取到每个元素;
 			2)给每个元素绑定上事件;
 			3)注意使用this区分当前操作的元素;
 			4)定时器不能只设一个了,应该给每个元素分配一个定时器,避免多个元素抢同一个定时器造成bug

 			记住:多物体运动不能共用同一个东西(某一参数,比如定时器)
 		***/
 			window.onload = function(){
 				var liEles = document.getElementsByTagName("li");

 				for(var i=0; i<liEles.length; i++){

 					//给每一个li元素定义一个定时器,避免多个元素抢同一个定时器造成bug
 					liEles[i].timer = null;
 					liEles[i].onmouseover = function(){

 						//传入this值,指定当前操作的是哪个li
 						playFun(this, 300);
 					};
 					liEles[i].onmouseout = function(){
 						playFun(this, 200);
 					};
 				}
 			}

 			//var timer = null;
 			function playFun(obj,itarget){
 				clearInterval(obj.timer);
 				obj.timer = setInterval(function(){
 					var speed = (itarget - obj.offsetWidth)/10;
 					speed = speed>0?Math.ceil(speed):Math.floor(speed);
 					
 					if(obj.offsetWidth == itarget){
 						clearInterval(obj.timer);
 					}else{
 						obj.style.width = obj.offsetWidth + speed + "px";
 					}
 				},50);
 			}
 		</script>
 	</head>
 	<body>
 		<ul>
 			<li></li>
 			<li></li>
 			<li></li>
 		</ul>
 	</body>
 </html>

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

ul li{
 			list-style:none;
 			width:200px;
 			height:100px;
 			background:green;
 			margin:20px;
 			<span style="color:#ff0000;">border:2px #ccc solid;</span>
 		}
然后在浏览器中运行代码,会发现物体在停止运动时并没有达到规定的目标值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)此法是课程中老师讲解的方法——封装一个专门获取属性值得方法,代码如下:

 <!DOCTYPE html>
 <html>
 	<head>
 		<meta charset="utf-8">
 		<style type="text/css">
 		*{
 			padding:0;
 			margin:0;
 		}
 		ul li{
 			list-style:none;
 			width:200px;
 			height:100px;
 			background:green;
 			margin:20px;
 			border:2px #ccc solid;
 		}
 		</style>
 		<script type="text/javascript">
 		/***
 			实现多物体运动的关键点:
 			1)获取到每个元素;
 			2)给每个元素绑定上事件;
 			3)注意使用this区分当前操作的元素;
 			4)定时器不能只设一个了,应该给每个元素分配一个定时器,避免多个元素抢同一个定时器造成bug

 			记住:多物体运动不能共用同一个东西(某一参数,比如定时器)
 		***/
 			window.onload = function(){
 				var liEles = document.getElementsByTagName("li");

 				for(var i=0; i<liEles.length; i++){

 					//给每一个li元素定义一个定时器,避免多个元素抢同一个定时器造成bug
 					liEles[i].timer = null;
 					liEles[i].onmouseover = function(){

 						//传入this值,指定当前操作的是哪个li
 						playFun(this, 300);
 					};
 					liEles[i].onmouseout = function(){
 						playFun(this, 200);
 					};
 				}
 			}

 			//var timer = null;
 			function playFun(obj,itarget){
 				clearInterval(obj.timer);
 				obj.timer = setInterval(function(){
 					var speed = (itarget - <span style="color:#ff0000;">parseInt(getStle(obj,"width"))</span>)/10;
 					speed = speed>0?Math.ceil(speed):Math.floor(speed);
 					
 					if(<span style="color:#ff0000;">parseInt(getStle(obj,"width"))</span> == itarget){
 						clearInterval(obj.timer);
 					}else{
 						//obj.style.width = obj.offsetWidth + speed + "px";
 						obj.style.width = <span style="color:#ff0000;">parseInt(getStle(obj,"width"))</span> + speed + "px";
 					}
 				},50);
 			}
 			//获取属性值
 			function getStle(ele,attr){ 
 				if(ele.currentStyle){ //兼容IE浏览器
 					return ele.currentStyle[attr];
 				}else{  //兼容firefox浏览器
 					return getComputedStyle(ele,false)[attr];
 				}
 			}</span>
 		</script>
 	</head>
 	<body>
 		<ul>
 			<li></li>
 			<li></li>
 			<li></li>
 		</ul>
 	</body>
 </html>

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

function playFun(obj,itarget){
 				clearInterval(obj.timer);
 				obj.timer = setInterval(function(){
 					var speed = (itarget - obj.clientWidth)/10;
 					speed = speed>0?Math.ceil(speed):Math.floor(speed);
 					
 					if(obj.clientWidth == itarget){
 						clearInterval(obj.timer);
 					}else{
 						obj.style.width = obj.clientWidth + speed + "px";
 					}
 				},50);
 			}

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

 <!DOCTYPE html>
 <html>
 	<head>
 		<meta charset="utf-8">
 		<style type="text/css">
 		*{
 			padding:0;
 			margin:0;
 		}
 		ul li{
 			list-style:none;
 			width:200px;
 			height:100px;
 			background:green;
 			margin:20px;
 			border:2px #ccc solid;
 			filter:alpha(opacity:30);
 			opacity:0.3;
 		}
 		</style>
 		<script type="text/javascript">
 			window.onload = function(){
 				var liEles = document.getElementsByTagName("li");

 				for(var i=0; i<liEles.length; i++){

 					//给每一个li元素定义一个定时器,避免多个元素抢同一个定时器造成bug
 					liEles[i].timer = null;
 					liEles[i].onmouseover = function(){

 						//传入this值,指定当前操作的是哪个li
 						//playFun(this, 300, "width");
 						playFun(this, 100, "opacity");
 					};
 					liEles[i].onmouseout = function(){
 						playFun(this, 30, "opacity");
 					};
 				}
 			}

 			function playFun(obj,itarget,attr){
 				clearInterval(obj.timer);
 				obj.timer = setInterval(function(){
 					var getValue = 0;
 					if(attr == "opacity"){

 						//parseFloat返回小数值
 						//由于计算机存储小数有误差,采用Math.round()四舍五入得整数
 						getValue = Math.round(parseFloat(getStle(obj,attr))*100);
 					}else{
 						getValue = parseInt(getStle(obj,attr));
 					}
 					
 					var speed = (itarget - getValue)/10;
 					speed = speed>0?Math.ceil(speed):Math.floor(speed);
 					
 					if(getValue == itarget){
 						clearInterval(obj.timer);
 					}else{
 						//obj.style[attr],采用中括号传参
 						if(attr == "opacity"){
 							getValue += speed;
 							obj.style["filter"] = "alpha(opacity:"+ getValue +")";
 							obj.style["opacity"] = getValue/100;
 						}else{
 							obj.style[attr] = getValue + speed + "px";
 						}
 						
 					}
 				},50);
 			}

 			//获取属性值
 			function getStle(ele,attr){ 
 				if(ele.currentStyle){ //兼容IE浏览器
 					return ele.currentStyle[attr];
 				}else{  //兼容firefox浏览器
 					return getComputedStyle(ele,false)[attr];
 				}
 			}
 		</script>
 	</head>
 	<body>
 		<ul>
 			<li></li>
 			<li></li>
 			<li></li>
 		</ul>
 	</body>
 </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、付费专栏及课程。

余额充值