[js高手之路]打造通用的匀速运动框架
本文,是接著上文[js高手之路]勻速運(yùn)動(dòng)與實(shí)例實(shí)戰(zhàn)(側(cè)邊欄,淡入淡出)繼續(xù)的,在這篇文章的最后,我們做了2個(gè)小實(shí)例:側(cè)邊欄與改變透明度的淡入淡出效果,本文我們把上文的animate函數(shù),繼續(xù)改造,讓他變得更加的通用和強(qiáng)大:
1,支持多個(gè)物體的運(yùn)動(dòng)
2,同時(shí)運(yùn)動(dòng)
3,順序運(yùn)動(dòng)
這三種運(yùn)動(dòng)方式也是jquery中animate函數(shù)支持的
一、animate函數(shù)中怎么區(qū)分變化不同的樣式?
上文中,側(cè)邊欄效果 用的animate函數(shù) 改變的是left值
1 function animate(obj, target, speed) { 2 clearInterval(timer); 3 timer = setInterval(function () { 4 if (obj.offsetLeft == target) { 5 clearInterval(timer); 6 } else { 7 obj.style.left = obj.offsetLeft + speed + 'px'; 8 } 9 }, 30); 10 }淡入淡出效果 用的animate函數(shù) 改變的是透明度
1 function animate(obj, target, speed) { 2 clearInterval(timer); 3 var cur = 0; 4 timer = setInterval(function () { 5 cur = css( obj, 'opacity') * 100; 6 if( cur == target ){ 7 clearInterval( timer ); 8 }else { 9 cur += speed; 10 obj.style.opacity = cur / 100; 11 obj.style.filter = "alpha(opacity:" + cur + ")"; 12 } 13 }, 30); 14 }而我們封裝的函數(shù),要變成通用的,首先面臨的問(wèn)題就是 這個(gè)函數(shù)要同時(shí)支持left值和透明度的變化,更通用的做法應(yīng)該是要支持所有的樣式變化,比如輪播功能,他有左右滑動(dòng),也有上下滑動(dòng)。
我們可以在獲取樣式和改變樣式的時(shí)候,做一下判斷就可以了,判斷分2類就能達(dá)到目的,因?yàn)槠渌麡邮? margin, left, top, right, font-size等等 )都是px,而透明度沒(méi)有px單位
1 function animate(obj, attr, target, speed) { 2 clearInterval(timer); 3 var cur = 0; 4 timer = setInterval(function () { 5 if (attr == 'opacity') { 6 cur = css(obj, 'opacity') * 100; 7 } else { 8 cur = parseInt(css(obj, attr)); 9 } 10 11 if (cur == target) { 12 clearInterval(timer); 13 } else { 14 if (attr == 'opacity') { 15 obj.style.opacity = ( cur + speed ) / 100; 16 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")"; 17 } else { 18 obj.style[attr] = cur + speed + "px"; 19 } 20 } 21 }, 30); 22 }合并之后的animate相比之前多了一個(gè)參數(shù)attr, 這個(gè)參數(shù)就是變化的樣式,obj: 變化的對(duì)象, target: 樣式需要變化到的目標(biāo)值. ?speed: 樣式每次變化的大小
如:
oImg.onmouseover = function () { animate(this, 'opacity', 100, 10); } oImg是獲取到的圖片對(duì)象. 這里各參數(shù)意思如下: this:當(dāng)前圖片對(duì)象 opacity: 變化的樣式是透明度 100: 鼠標(biāo)移到圖片上時(shí),透明度變成100 10: 透明度每次在原來(lái)的基礎(chǔ)上加10 1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>合并的運(yùn)動(dòng) - by ghostwu</title> 6 <style> 7 img { 8 border: none; 9 opacity: 0.3; 10 filter: alpha(opacity:30); 11 position: absolute; 12 left: 200px; 13 } 14 15 #box { 16 width: 150px; 17 height: 300px; 18 background: red; 19 position: absolute; 20 left: -150px; 21 top: 50px; 22 } 23 24 #box div { 25 width: 28px; 26 height: 100px; 27 position: absolute; 28 right: -28px; 29 top: 100px; 30 background: green; 31 } 32 </style> 33 <script> 34 window.onload = function () { 35 var oImg = document.getElementById("img"), 36 oBox = document.getElementById("box"), 37 timer = null; 38 39 oImg.onmouseover = function () { 40 animate(this, 'opacity', 100, 10); 41 } 42 oImg.onmouseout = function () { 43 animate(this, 'opacity', 30, -10); 44 } 45 46 oBox.onmouseover = function () { 47 animate(this, 'left', 0, 10); 48 } 49 50 oBox.onmouseout = function () { 51 animate(this, 'left', -150, -10); 52 } 53 54 function animate(obj, attr, target, speed) { 55 clearInterval(timer); 56 var cur = 0; 57 timer = setInterval(function () { 58 if (attr == 'opacity') { 59 cur = css(obj, 'opacity') * 100; 60 } else { 61 cur = parseInt(css(obj, attr)); 62 } 63 64 if (cur == target) { 65 clearInterval(timer); 66 } else { 67 if (attr == 'opacity') { 68 obj.style.opacity = ( cur + speed ) / 100; 69 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")"; 70 } else { 71 obj.style[attr] = cur + speed + "px"; 72 } 73 } 74 }, 30); 75 } 76 77 function css(obj, attr) { 78 if (obj.currentStyle) { 79 return obj.currentStyle[attr]; 80 } else { 81 return getComputedStyle(obj, false)[attr]; 82 } 83 } 84 } 85 </script> 86 </head> 87 <body> 88 <div id="box"> 89 <div>分享到</div> 90 </div> 91 <img src="./img/h4.jpg" alt="" id="img"/> 92 </body> 93 </html> View Code上述就是完整的代碼實(shí)例,請(qǐng)自行展開(kāi),點(diǎn)擊run code預(yù)覽效果?
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> img { border: none; opacity: 0.3; filter: alpha(opacity:30); position: absolute; left: 200px; } #box { width: 150px; height: 300px; background: red; position: absolute; left: -150px; top: 50px; } #box div { width: 28px; height: 100px; position: absolute; right: -28px; top: 100px; background: green; } </style> <script> window.onload = function () { var oImg = document.getElementById("img"), oBox = document.getElementById("box"), timer = null; oImg.onmouseover = function () { animate(this, 'opacity', 100, 10); } oImg.onmouseout = function () { animate(this, 'opacity', 30, -10); } oBox.onmouseover = function () { animate(this, 'left', 0, 10); } oBox.onmouseout = function () { animate(this, 'left', -150, -10); } function animate(obj, attr, target, speed) { clearInterval(timer); var cur = 0; timer = setInterval(function () { if (attr == 'opacity') { cur = css(obj, 'opacity') * 100; } else { cur = parseInt(css(obj, attr)); } if (cur == target) { clearInterval(timer); } else { if (attr == 'opacity') { obj.style.opacity = ( cur + speed ) / 100; obj.style.filter = "alpha(opacity:" + (cur + speed) + ")"; } else { obj.style[attr] = cur + speed + "px"; } } }, 30); } function css(obj, attr) { if (obj.currentStyle) { return obj.currentStyle[attr]; } else { return getComputedStyle(obj, false)[attr]; } } } </script> </head> <body> <div id="box"> <div>分享到</div> </div> <img src="http://images2017.cnblogs.com/blog/253192/201710/253192-20171015095909480-1867777993.png" alt="" id="img"/> </body> </html>run code 當(dāng)你分別測(cè)試這兩個(gè)功能的時(shí)候: 移動(dòng)到圖片上然后移出來(lái) 移動(dòng)到分享到,然后移出來(lái) 這樣是沒(méi)有問(wèn)題的 如果你這樣測(cè)試: 移動(dòng)到 分享到,然后迅速又移動(dòng)到圖片上, 這個(gè)時(shí)候你會(huì)發(fā)現(xiàn) 分享到 停下來(lái)了,這就不符合邏輯了! 按道理來(lái)說(shuō),鼠標(biāo)移動(dòng)到圖片上,相當(dāng)于觸發(fā)了 “分享到” 的mouseout( 鼠標(biāo)移出事件 ),那么 ?"分享到" 這個(gè)時(shí)候要隱藏,并不是停止。 為什么會(huì)這樣呢?因?yàn)檫@兩個(gè)運(yùn)動(dòng)共享了一個(gè)定時(shí)器,當(dāng)鼠標(biāo)移動(dòng)到圖片上,開(kāi)啟定時(shí)器的時(shí)候,把“分享到”的定時(shí)器給停了。那么再做多物體運(yùn)動(dòng)的時(shí)候,我們就要把定時(shí)器拆分,每個(gè)對(duì)象都要有一個(gè)定時(shí)器,怎么做呢? 非常簡(jiǎn)單,不要定義一個(gè)簡(jiǎn)單的timer變量,我們只要把timer加在obj對(duì)象上,那么每個(gè)對(duì)象都有一個(gè)timer屬性,就達(dá)到定時(shí)器的分離效果了 修改之后的完整代碼如下,請(qǐng)自行展開(kāi): 1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Document</title> 6 <style> 7 img { 8 border: none; 9 opacity: 0.3; 10 filter: alpha(opacity:30); 11 position: absolute; 12 left: 200px; 13 } 14 15 #box { 16 width: 150px; 17 height: 300px; 18 background: red; 19 position: absolute; 20 left: -150px; 21 top: 50px; 22 } 23 24 #box div { 25 width: 28px; 26 height: 100px; 27 position: absolute; 28 right: -28px; 29 top: 100px; 30 background: green; 31 } 32 </style> 33 <script> 34 window.onload = function () { 35 var oImg = document.getElementById("img"), 36 oBox = document.getElementById("box"); 37 38 oImg.onmouseover = function () { 39 animate(this, 'opacity', 100, 10); 40 } 41 oImg.onmouseout = function () { 42 animate(this, 'opacity', 30, -10); 43 } 44 45 oBox.onmouseover = function () { 46 animate(this, 'left', 0, 10); 47 } 48 49 oBox.onmouseout = function () { 50 animate(this, 'left', -150, -10); 51 } 52 53 function animate(obj, attr, target, speed) { 54 clearInterval(obj.timer); 55 var cur = 0; 56 obj.timer = setInterval(function () { 57 if (attr == 'opacity') { 58 cur = css(obj, 'opacity') * 100; 59 } else { 60 cur = parseInt(css(obj, attr)); 61 } 62 63 if (cur == target) { 64 clearInterval(obj.timer); 65 } else { 66 if (attr == 'opacity') { 67 obj.style.opacity = ( cur + speed ) / 100; 68 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")"; 69 } else { 70 obj.style[attr] = cur + speed + "px"; 71 } 72 } 73 }, 30); 74 } 75 76 function css(obj, attr) { 77 if (obj.currentStyle) { 78 return obj.currentStyle[attr]; 79 } else { 80 return getComputedStyle(obj, false)[attr]; 81 } 82 } 83 } 84 </script> 85 </head> 86 <body> 87 <div id="box"> 88 <div>分享到</div> 89 </div> 90 <img src="./img/h4.jpg" alt="" id="img"/> 91 </body> 92 </html> View Code
至此,我們就完成了多物體運(yùn)動(dòng)與不同樣式的修改
二、讓animate函數(shù)支持多個(gè)樣式同時(shí)改變
比如:
oBox.onmouseover = function(){
animate( this, { "width" : 500, "height" : 400 }, 10 );
}
oBox是一個(gè)div元素,animate各參數(shù)的意思:
this: 當(dāng)前div元素
{width : 500, "height" : 400 } : 把寬度變成500, 高度變成400,這兩個(gè)樣式要在同一時(shí)間完成,
10: 樣式每次在原來(lái)的基礎(chǔ)上變化10(如width初始值200--> 210, 220, 230.....)
完整的同時(shí)運(yùn)動(dòng)變化 代碼:
1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Document</title> 6 <style> 7 div { 8 width: 200px; 9 height: 200px; 10 background: red; 11 } 12 </style> 13 <script> 14 window.onload = function () { 15 var oBox = document.getElementById("box"); 16 oBox.onmouseover = function(){ 17 // animate( this, { "width" : 500, "height" : 500 }, 10 ); 18 animate( this, { "width" : 500, "height" : 400 }, 10 ); 19 } 20 21 function animate(obj, attr, speed) { 22 clearInterval(obj.timer); 23 var cur = 0; 24 obj.timer = setInterval(function () { 25 for ( var key in attr ) { 26 if (key == 'opacity') { 27 cur = css(obj, 'opacity') * 100; 28 } else { 29 cur = parseInt(css(obj, key)); 30 } 31 var target = attr[key]; 32 if (cur == target) { 33 clearInterval(obj.timer); 34 } else { 35 if (key == 'opacity') { 36 obj.style.opacity = ( cur + speed ) / 100; 37 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")"; 38 } else { 39 obj.style[key] = cur + speed + "px"; 40 } 41 } 42 } 43 }, 30); 44 } 45 46 function css(obj, attr) { 47 if (obj.currentStyle) { 48 return obj.currentStyle[attr]; 49 } else { 50 return getComputedStyle(obj, false)[attr]; 51 } 52 } 53 } 54 </script> 55 </head> 56 <body> 57 <div id="box"></div> 58 </body> 59 </html> View Code請(qǐng)自行展開(kāi)這段代碼,這段代碼能夠同時(shí)運(yùn)動(dòng),但是有一個(gè)問(wèn)題:
div的初始寬度與高度( width : 200, height : 200)
變化步長(zhǎng)一樣( 10 )
變化時(shí)間一樣( 每30毫秒變化一次 )
目標(biāo)( width: 500, height : 400 )
你能想到什么問(wèn)題嗎?( 兩個(gè)人在同一起跑線上,速度一樣, 時(shí)間一樣,但是要同時(shí)到達(dá)不同的目標(biāo),一個(gè)500, 一個(gè)400 )
答案是很明顯的,肯定是目標(biāo)近的( height : 400 )那個(gè)先到達(dá),然后把對(duì)象上的定時(shí)器關(guān)了,另一個(gè)目標(biāo)更遠(yuǎn)的( width: 500 )肯定到達(dá)不了
你可以在這句代碼下面,輸出當(dāng)前的值和目標(biāo)值:
var target = attr[key]; console.log( key, cur, target );輸出來(lái)的結(jié)果是:
?
?
?從上圖可以看出,height已經(jīng)達(dá)到了400px,但是width停在了410px,為什么不是400px ? 因?yàn)閣idth = 400的時(shí)候, 就是( cur == 500 ) 相當(dāng)于( 400 == 500 ) 不成立,所以執(zhí)行了else語(yǔ)句,width = cur + 10 = 400 + 10 = 410,然后height到達(dá)400px停止了定時(shí)器,所以width停在了410px.
那么我們?cè)趺唇鉀Q這個(gè)問(wèn)題呢?
其實(shí)也好辦,就是height = 400的時(shí)候 不要把定時(shí)器關(guān)了,應(yīng)該等width = 500的時(shí)候再關(guān)閉定時(shí)器,不就在同一時(shí)間,完成了同時(shí)到達(dá)目標(biāo)的效果嗎?
修改后的代碼如下:
1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Document</title> 6 <style> 7 div { 8 width: 200px; 9 height: 200px; 10 background: red; 11 } 12 </style> 13 <script> 14 window.onload = function () { 15 var oBox = document.getElementById("box"); 16 oBox.onmouseover = function(){ 17 animate( this, { "width" : 500, "height" : 400 }, 10 ); 18 } 19 20 function animate(obj, attr, speed) { 21 clearInterval(obj.timer); 22 var cur = 0; 23 obj.timer = setInterval(function () { 24 var bFlag = true; 25 for ( var key in attr ) { 26 if (key == 'opacity') { 27 cur = css(obj, 'opacity') * 100; 28 } else { 29 cur = parseInt(css(obj, key)); 30 } 31 var target = attr[key]; 32 if (cur != target) { 33 bFlag = false; 34 if (key == 'opacity') { 35 obj.style.opacity = ( cur + speed ) / 100; 36 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")"; 37 } else { 38 obj.style[key] = cur + speed + "px"; 39 } 40 } 41 } 42 if ( bFlag ) { 43 clearInterval( obj.timer ); 44 } 45 }, 30); 46 } 47 48 function css(obj, attr) { 49 if (obj.currentStyle) { 50 return obj.currentStyle[attr]; 51 } else { 52 return getComputedStyle(obj, false)[attr]; 53 } 54 } 55 } 56 </script> 57 </head> 58 <body> 59 <div id="box"></div> 60 </body> 61 </html> View Code聲明一個(gè)變量,每次變化完一次( width, height )樣式 把bFlag = true, 只要在for循環(huán)中有一個(gè)沒(méi)有到達(dá)目標(biāo),bFlag的值都是false,這樣就不會(huì)關(guān)閉定時(shí)器。當(dāng)兩個(gè)都到達(dá)目標(biāo),才關(guān)閉定時(shí)器.
三、順序運(yùn)動(dòng)
?如樣式變化,按順序來(lái),不是同時(shí)變化, 如:
oBox.onmouseover = function(){
//回調(diào)函數(shù): 把函數(shù)當(dāng)做參數(shù)傳遞給另一個(gè)函數(shù)
animate( this, { 'width' : 500 }, 10, function(){
animate( this, { 'height' : 500 }, 10 );
} );
}
當(dāng)把width變成500px的時(shí)候,如果傳遞了回調(diào)函數(shù), 再接著執(zhí)行回調(diào)函數(shù)里面的運(yùn)動(dòng)
修改后的完整代碼:
1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title>通用的勻速運(yùn)動(dòng)框架 - by ghostwu</title> 6 <style> 7 div { 8 width: 200px; 9 height: 200px; 10 background: red; 11 } 12 </style> 13 <script> 14 window.onload = function () { 15 var oBox = document.getElementById("box"); 16 oBox.onmouseover = function(){ 17 //回調(diào)函數(shù): 把函數(shù)當(dāng)做參數(shù)傳遞給另一個(gè)函數(shù) 18 animate( this, { 'width' : 500 }, 10, function(){ 19 animate( this, { 'height' : 500 }, 10 ); 20 } ); 21 } 22 23 function animate(obj, attr, speed, fn ) { 24 25 clearInterval(obj.timer); 26 var cur = 0; 27 obj.timer = setInterval(function () { 28 var bFlag = true; 29 for (var key in attr) { 30 if (key == 'opacity') { 31 cur = css(obj, 'opacity') * 100; 32 } else { 33 cur = parseInt(css(obj, key)); 34 } 35 var target = attr[key]; 36 if (cur != target) { 37 bFlag = false; 38 if (key == 'opacity') { 39 obj.style.opacity = ( cur + speed ) / 100; 40 obj.style.filter = "alpha(opacity:" + (cur + speed) + ")"; 41 } else { 42 obj.style[key] = cur + speed + "px"; 43 } 44 } 45 } 46 47 if (bFlag) { 48 clearInterval(obj.timer); 49 fn && fn.call( obj ); 50 } 51 }, 30); 52 } 53 54 function css(obj, attr) { 55 if (obj.currentStyle) { 56 return obj.currentStyle[attr]; 57 } else { 58 return getComputedStyle(obj, false)[attr]; 59 } 60 } 61 } 62 </script> 63 </head> 64 <body> 65 <div id="box"></div> 66 </body> 67 </html> View Code??
總結(jié)
以上是生活随笔為你收集整理的[js高手之路]打造通用的匀速运动框架的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 组件和模块间Activity路由框架
- 下一篇: 30-35岁职场规划深谈,字字戳心