實例1——控制一個對象的勻速移動和停止
HTML:
<input id="btn" type="button" value=" Move It ! "/> <div id="d1"> <img id="i1" src="1.jpg" alt/> </div>
JS:實現向右運動
var timer=null; window.onload=function(){ var odiv=document.getElementById('d1'); var obtn=document.getElementById('btn'); clearInterval(timer); //作用見要點① obtn.onclick=function(){ timer=setInterval(function(){ var speed=10; if(odiv.offsetLeft>=300){ //判斷對象邊距 到達指定位移則關閉定時器 clearInterval(timer); }else{ odiv.style.left=odiv.offsetLeft+speed+'px'; } },30); } }
要點:
①if語句的條件不能用“==”運算符,如上述代碼,當speed的值為基數如7時,不斷增加的左邊距不會出現300px值,而是到達294后直接跳到301,導致條件失效,無法停止。
②使用else語句是防止停止移動后,每點擊一次按鈕,div任會移動一個speed。
③在定時器之前,先關閉一下定時器,防止連續點擊按鈕時,同時打開多個定時器,使移動速度疊加后更快。
封裝:
//object:要移動的對象id itarget:水平位移位置
var timer=null; function moveto(object,itarget){ var obj=document.getElementById(object); clearInterval(timer); timer=setInterval(function(){ var speed=0; if(obj.offsetLeft<itarget){ //通過對象距離父級的邊距和水平位移量 判斷左右位移方向 speed=10; }else{ speed=-10; } if(obj.offsetLeft==itarget){ clearInterval(timer); }else{ obj.style.left=obj.offsetLeft+speed+'px'; }; },30); }
實例2——修改上述封裝的函數moveto(),使該對象變速停止
JS:
var timer=null; function moveto(object,itarget){ var obj=document.getElementById(object); clearInterval(timer); timer=setInterval(function(){ var speed=0; if(obj.offsetLeft<itarget){//通過位移量除以10,使speed遞減,實現減速停止。 乘以10則為加速。通過乘除的數字,控制快慢
speed=(itarget-obj.offsetLeft)/10; }else{ speed=-(obj.offsetLeft-itarget)/10; } speed=speed>0?Math.ceil(speed):Math.floor(speed);//取整,解決最后不足1px的位移量被忽略的問題 if(obj.offsetLeft==itarget){ clearInterval(timer); }else{ obj.style.left=obj.offsetLeft+speed+'px'; }; document.title=obj.offsetLeft; },30); }
要點:
①通過遞減speed值,實現變速。
②移動到最后,當像素小於1px時,小於1px的幾個值不會被添加(或減去)到對象left中,而是被忽略,所以最終位移量比設定的水平位移位置itarget要少幾個像素。解決的辦法是進行取整:正數向上取整ceil(),負數向下取整floor()。
擴展:垂直位移的原理和水平位移的相同。
補充1:
解決speed與itarget不能整除,導致對象不能精確到達itarget位置,而是在其左右抖動問題:
var timer=null; function moveto(object,itarget){ var obj=document.getElementById(object); clearInterval(timer); timer=setInterval(function(){ var speed=0; if(obj.offsetLeft<=itarget){ speed=7; }else{ speed=-7; } //設置對象在離目標位置itarget的距離小於speed時,停止運動,同時設置對象的left直接移動到itarget的位置。 if(Math.abs(itarget-obj.offsetLeft<=speed)){ clearInterval(timer); obj.style.left=itarget+'px'; }else{ obj.style.left=obj.offsetLeft+speed+'px'; }; document.title=obj.offsetLeft; },30); }
補充2:
offset的Bug:例如offsetWidth,它包含的不只是width,還包含padding和border。當給對象設置了填充或邊框時,再將offsetWidth賦值給對象時,就會運動就會有差異。
解決:不用offset,而是通過創建一個兼容IE和FF的函數,獲取元素的width屬性值,來代替offsetWidth。該函數如下:getAttr()
function getAttr(obj,attrName){ var obj=document.getElementById(obj); if(obj.currentStyle){ return obj.currentStyle[attrName]; //兼容IE }else{ return getComputedStyle(obj,false)[attrName]; //兼容FF } }