打造通用的勻速運(yùn)動(dòng)框架(實(shí)例講解)
本文,是接著上 基于勻速運(yùn)動(dòng)的實(shí)例講解(側(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值
function animate(obj, target, speed) {
clearInterval(timer);
timer = setInterval(function () {
if (obj.offsetLeft == target) {
clearInterval(timer);
} else {
obj.style.left = obj.offsetLeft + speed + 'px';
}
}, 30);
}
淡入淡出效果 用的animate函數(shù) 改變的是透明度
function animate(obj, target, speed) {
clearInterval(timer);
var cur = 0;
timer = setInterval(function () {
cur = css( obj, 'opacity') * 100;
if( cur == target ){
clearInterval( timer );
}else {
cur += speed;
obj.style.opacity = cur / 100;
obj.style.filter = "alpha(opacity:" + cur + ")";
}
}, 30);
}
而我們封裝的函數(shù),要變成通用的,首先面臨的問題就是 這個(gè)函數(shù)要同時(shí)支持left值和透明度的變化,更通用的做法應(yīng)該是要支持所有的樣式變化,比如輪播功能,他有左右滑動(dòng),也有上下滑動(dòng)。
我們可以在獲取樣式和改變樣式的時(shí)候,做一下判斷就可以了,判斷分2類就能達(dá)到目的,因?yàn)槠渌麡邮? margin, left, top, right, font-size等等 )都是px,而透明度沒有px單位
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);
}
合并之后的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: 透明度每次在原來的基礎(chǔ)上加10
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>合并的運(yùn)動(dòng) - by ghostwu</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="./img/h4.jpg" alt="" id="img"/>
</body>
</html>
上述就是完整的代碼實(shí)例。
當(dāng)你分別測(cè)試這兩個(gè)功能的時(shí)候:
移動(dòng)到圖片上然后移出來
移動(dòng)到分享到,然后移出來
這樣是沒有問題的
如果你這樣測(cè)試:
移動(dòng)到 分享到,然后迅速又移動(dòng)到圖片上, 這個(gè)時(shí)候你會(huì)發(fā)現(xiàn) 分享到 停下來了,這就不符合邏輯了! 按道理來說,鼠標(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)到圖片上,開啟定時(shí)器的時(shí)候,把“分享到”的定時(shí)器給停了。那么再做多物體運(yùn)動(dòng)的時(shí)候,我們就要把定時(shí)器拆分,每個(gè)對(duì)象都要有一個(gè)定時(shí)器,怎么做呢? 非常簡單,不要定義一個(gè)簡單的timer變量,我們只要把timer加在obj對(duì)象上,那么每個(gè)對(duì)象都有一個(gè)timer屬性,就達(dá)到定時(shí)器的分離效果了
修改之后的完整代碼如下,請(qǐng)自行展開:
<!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");
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(obj.timer);
var cur = 0;
obj.timer = setInterval(function () {
if (attr == 'opacity') {
cur = css(obj, 'opacity') * 100;
} else {
cur = parseInt(css(obj, attr));
}
if (cur == target) {
clearInterval(obj.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="./img/h4.jpg" alt="" id="img"/>
</body>
</html>
至此,我們就完成了多物體運(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: 樣式每次在原來的基礎(chǔ)上變化10(如width初始值200--> 210, 220, 230.....)
完整的同時(shí)運(yùn)動(dòng)變化 代碼:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
div {
width: 200px;
height: 200px;
background: red;
}
</style>
<script>
window.onload = function () {
var oBox = document.getElementById("box");
oBox.onmouseover = function(){
// animate( this, { "width" : 500, "height" : 500 }, 10 );
animate( this, { "width" : 500, "height" : 400 }, 10 );
}
function animate(obj, attr, speed) {
clearInterval(obj.timer);
var cur = 0;
obj.timer = setInterval(function () {
for ( var key in attr ) {
if (key == 'opacity') {
cur = css(obj, 'opacity') * 100;
} else {
cur = parseInt(css(obj, key));
}
var target = attr[key];
if (cur == target) {
clearInterval(obj.timer);
} else {
if (key == 'opacity') {
obj.style.opacity = ( cur + speed ) / 100;
obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
} else {
obj.style[key] = 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>
</body>
</html>
請(qǐng)自行展開這段代碼,這段代碼能夠同時(shí)運(yùn)動(dòng),但是有一個(gè)問題:
div的初始寬度與高度( width : 200, height : 200)
變化步長一樣( 10 )
變化時(shí)間一樣( 每30毫秒變化一次 )
目標(biāo)( width: 500, height : 400 )
你能想到什么問題嗎?( 兩個(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 );
輸出來的結(jié)果是:


從上圖可以看出,height已經(jīng)達(dá)到了400px,但是width停在了410px,為什么不是400px ? 因?yàn)閣idth = 400的時(shí)候, 就是( cur == 500 ) 相當(dāng)于( 400 == 500 ) 不成立,所以執(zhí)行了else語句,width = cur + 10 = 400 + 10 = 410,然后height到達(dá)400px停止了定時(shí)器,所以width停在了410px.
那么我們?cè)趺唇鉀Q這個(gè)問題呢?
其實(shí)也好辦,就是height = 400的時(shí)候 不要把定時(shí)器關(guān)了,應(yīng)該等width = 500的時(shí)候再關(guān)閉定時(shí)器,不就在同一時(shí)間,完成了同時(shí)到達(dá)目標(biāo)的效果嗎?
修改后的代碼如下:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
div {
width: 200px;
height: 200px;
background: red;
}
</style>
<script>
window.onload = function () {
var oBox = document.getElementById("box");
oBox.onmouseover = function(){
animate( this, { "width" : 500, "height" : 400 }, 10 );
}
function animate(obj, attr, speed) {
clearInterval(obj.timer);
var cur = 0;
obj.timer = setInterval(function () {
var bFlag = true;
for ( var key in attr ) {
if (key == 'opacity') {
cur = css(obj, 'opacity') * 100;
} else {
cur = parseInt(css(obj, key));
}
var target = attr[key];
if (cur != target) {
bFlag = false;
if (key == 'opacity') {
obj.style.opacity = ( cur + speed ) / 100;
obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
} else {
obj.style[key] = cur + speed + "px";
}
}
}
if ( bFlag ) {
clearInterval( obj.timer );
}
}, 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>
</body>
</html>
聲明一個(gè)變量,每次變化完一次( width, height )樣式 把bFlag = true, 只要在for循環(huán)中有一個(gè)沒有到達(dá)目標(biāo),bFlag的值都是false,這樣就不會(huì)關(guān)閉定時(shí)器。當(dāng)兩個(gè)都到達(dá)目標(biāo),才關(guān)閉定時(shí)器.
三、順序運(yùn)動(dòng)
如樣式變化,按順序來,不是同時(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)
修改后的完整代碼:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>通用的勻速運(yùn)動(dòng)框架 - by ghostwu</title>
<style>
div {
width: 200px;
height: 200px;
background: red;
}
</style>
<script>
window.onload = function () {
var oBox = document.getElementById("box");
oBox.onmouseover = function(){
//回調(diào)函數(shù): 把函數(shù)當(dāng)做參數(shù)傳遞給另一個(gè)函數(shù)
animate( this, { 'width' : 500 }, 10, function(){
animate( this, { 'height' : 500 }, 10 );
} );
}
function animate(obj, attr, speed, fn ) {
clearInterval(obj.timer);
var cur = 0;
obj.timer = setInterval(function () {
var bFlag = true;
for (var key in attr) {
if (key == 'opacity') {
cur = css(obj, 'opacity') * 100;
} else {
cur = parseInt(css(obj, key));
}
var target = attr[key];
if (cur != target) {
bFlag = false;
if (key == 'opacity') {
obj.style.opacity = ( cur + speed ) / 100;
obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
} else {
obj.style[key] = cur + speed + "px";
}
}
}
if (bFlag) {
clearInterval(obj.timer);
fn && fn.call( obj );
}
}, 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>
</body>
</html>
以上這篇打造通用的勻速運(yùn)動(dòng)框架(實(shí)例講解)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
教你修改element-ui源碼給el-dialog添加全屏功能
el-dialog組件提供了fullscreen功能,但是無法滿足業(yè)務(wù)需求。系統(tǒng)使用了許多dialog,不方便重新封裝dialog組件,故直接對(duì)源碼進(jìn)行修改,這篇文章主要介紹了修改element-ui源碼給el-dialog添加全屏功能,需要的朋友可以參考下2022-11-11
JS使用setInterval實(shí)現(xiàn)的簡單計(jì)時(shí)器功能示例
這篇文章主要介紹了JS使用setInterval實(shí)現(xiàn)的簡單計(jì)時(shí)器功能,涉及javascript基于setInterval的定時(shí)觸發(fā)與數(shù)值運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2018-04-04
基于bootstrap插件實(shí)現(xiàn)autocomplete自動(dòng)完成表單
這篇文章主要介紹了基于bootstrap插件實(shí)現(xiàn)autocomplete自動(dòng)完成表單的相關(guān)資料,感興趣的朋友可以參考一下2016-05-05
Bootstrap Navbar Component實(shí)現(xiàn)響應(yīng)式導(dǎo)航
這篇文章主要介紹了Bootstrap Navbar Component實(shí)現(xiàn)響應(yīng)式導(dǎo)航的相關(guān)資料,講解了Bootstrap Navbar應(yīng)用及源碼解析,需要的朋友可以參考下2016-10-10
淺談ES6中箭頭函數(shù)與普通函數(shù)的區(qū)別
箭頭函數(shù)是ES6中一種新的函數(shù)的表達(dá)式,本文就來介紹一下ES6中箭頭函數(shù)與普通函數(shù)的區(qū)別,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2023-05-05
element-ui 圖片壓縮上傳功能實(shí)現(xiàn)
這篇文章主要介紹了element-ui 圖片壓縮上傳功能實(shí)現(xiàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-10-10

