JavaScript動(dòng)畫(huà)函數(shù)封裝詳解
一、動(dòng)畫(huà)函數(shù)原理
核心原理:通過(guò)定時(shí)器setInterval() 不斷移動(dòng)盒子位置。
實(shí)現(xiàn)步驟:
- 獲得盒子當(dāng)前位置
- 讓盒子在當(dāng)前位置加上1個(gè)移動(dòng)距離
- 利用定時(shí)器不斷重復(fù)這個(gè)操作
- 加一個(gè)結(jié)束定時(shí)器的條件
- 注意此元素需要添加定位,才能使用element.style.left
如下所示:
給定一個(gè)盒子,讓其慢慢移動(dòng)到300px的位置。
代碼如下:
<style>
div{
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
background-color: cyan;
}
</style>
</head>
<body>
<div></div>
<script>
var div = document.querySelector('div');
var timer = setInterval(function(){
if(div.offsetLeft >= 300){
clearInterval(timer);
}
div.style.left = div.offsetLeft + 1 +'px';
},30);
</script>
</body>
運(yùn)行結(jié)果為:

運(yùn)行成功。
但是如果同時(shí)有好幾個(gè)元素都需要添加動(dòng)畫(huà)呢?我們就可以考慮將其封裝成一個(gè)簡(jiǎn)單的動(dòng)畫(huà)函數(shù)。
二、動(dòng)畫(huà)函數(shù)簡(jiǎn)單封裝
函數(shù)需要傳遞2個(gè)參數(shù),動(dòng)畫(huà)對(duì)象和移動(dòng)到的距離。如下所示:
function animate(obj,target){
var timer = setInterval(function(){
if(obj.offsetLeft >= target){
clearInterval(timer);
}
obj.style.left = obj.offsetLeft + 1 +'px';
},30);
}
我們就可以通過(guò)調(diào)用上述封裝的函數(shù)來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果。例如,給定兩個(gè)不同的盒子,分別調(diào)用動(dòng)畫(huà)函數(shù):
<style>
.box1{
position: absolute;
left: 0;
top: 50px;
width: 100px;
height: 100px;
background-color: cyan;
}
.box2{
position: absolute;
left: 0;
top: 155px;
width: 150px;
height: 150px;
background-color: deepskyblue;
}
</style>
<body>
<div class="box1"></div>
<div class="box2"></div>
<script>
function animate(obj,target){
var timer = setInterval(function(){
if(obj.offsetLeft >= target){
clearInterval(timer);
}
obj.style.left = obj.offsetLeft + 1 +'px';
},30);
}
var box1 = document.querySelector('.box1');
var box2 = document.querySelector('.box2');
animate(box1,300);
animate(box2,400);
</script>
</body>
效果為:

成功實(shí)現(xiàn)了動(dòng)畫(huà)的效果。
但是上面封裝的動(dòng)畫(huà)函數(shù)還是有問(wèn)題的,每當(dāng)我們調(diào)用一次動(dòng)畫(huà)函數(shù),就會(huì)給我們開(kāi)辟一塊內(nèi)存空間,會(huì)造成浪費(fèi)內(nèi)存資源的問(wèn)題,而且我們每次調(diào)用的動(dòng)畫(huà)函數(shù)都是以同一個(gè)名字命名的,很容易引起歧義,所以我們就可以給不同的元素使用不同的定時(shí)器(自己專(zhuān)門(mén)用自己的定時(shí)器)。
三、 動(dòng)畫(huà)函數(shù)給不同元素記錄不同定時(shí)器
核心原理:利用 JS 是一門(mén)動(dòng)態(tài)語(yǔ)言,可以很方便的給當(dāng)前對(duì)象添加屬性。
通過(guò)給對(duì)象添加屬性的方法給給不同的元素添加定時(shí)器,我們可以將其進(jìn)行如下的封裝:
function animate(obj,target){
obj.timer = setInterval(function(){
if(obj.offsetLeft >= target){
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + 1 +'px';
},30);
}
當(dāng)然,如果我們想要讓某個(gè)元素在我們進(jìn)行一系列操作后才實(shí)現(xiàn)動(dòng)畫(huà)效果的話,我們就可以給其添加特定事件,然后將函數(shù)調(diào)用寫(xiě)在事件中,
以第一個(gè)例子為例,給它添加點(diǎn)擊事件,當(dāng)點(diǎn)擊按鈕后,才讓這個(gè)盒子發(fā)生移動(dòng):
var box1 = document.querySelector('.box1');
var btn = document.querySelector('button')
btn.addEventListener('click',function(){
animate(box1,300);
})
效果為:

效果實(shí)現(xiàn),但是如果我們一直點(diǎn)擊按鈕,會(huì)出現(xiàn)什么情況呢?

我們會(huì)發(fā)現(xiàn),當(dāng)我們不斷點(diǎn)擊按鈕時(shí),盒子運(yùn)行的速度會(huì)越來(lái)越快,這是因?yàn)槲覀兺瑫r(shí)開(kāi)啟了太多定時(shí)器。該如何解決呢?方案就是讓我們的元素先清除以前的定時(shí)器,只保留一個(gè)定時(shí)器執(zhí)行,所以,我們就可以在函數(shù)的最上面添加一個(gè)清除定時(shí)器的操作。代碼為:
function animate(obj,target){
clearInterval(obj.timer);
obj.timer = setInterval(function(){
if(obj.offsetLeft >= target){
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + 1 +'px';
},30);
}
var box1 = document.querySelector('.box1');
var btn = document.querySelector('button');
btn.addEventListener('click',function(){
animate(box1,300);
})
此時(shí)的運(yùn)行效果為
成功實(shí)現(xiàn)。
通過(guò)上述一系列操作,我們可以發(fā)現(xiàn),我們所實(shí)現(xiàn)的動(dòng)畫(huà)都是勻速的,為了讓效果更加好看,我們可以讓我們的動(dòng)畫(huà)以緩動(dòng)的速度運(yùn)行。

四、緩動(dòng)效果原理
緩動(dòng)動(dòng)畫(huà)就是讓元素運(yùn)動(dòng)速度有所變化,最常見(jiàn)的是讓速度慢慢停下來(lái)。
- 思路:讓盒子每次移動(dòng)的距離慢慢變小,速度就會(huì)慢慢落下來(lái)。
- 核心算法: (目標(biāo)值 - 現(xiàn)在的位置 ) / 10 做為每次移動(dòng)的距離 步長(zhǎng)
- 停止的條件: 讓當(dāng)前盒子位置等于目標(biāo)位置就停止定時(shí)器
注意步長(zhǎng)值需要取整
以上個(gè)例子為例,當(dāng)我們點(diǎn)擊按鈕時(shí),讓元素以緩動(dòng)的速度移動(dòng),我們可以將封裝的動(dòng)畫(huà)函數(shù)改為:
function animate(obj,target){
clearInterval(obj.timer)
obj.timer = setInterval(function(){
var step = (target - obj.offsetLeft)/10;
if(obj.offsetLeft == target){
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + step +'px';
},30);
}
實(shí)現(xiàn)效果為:

這樣的效果是不是更好看了呢?但是我們來(lái)檢查一下我們的元素具體移動(dòng)了多大距離,是不是剛好到目標(biāo)值300px的位置呢?

通過(guò)檢查我們發(fā)現(xiàn),我們的元素并沒(méi)有到指定位置,這是因?yàn)槲覀兊牟介L(zhǎng)公式是有問(wèn)題的,進(jìn)行除法運(yùn)算時(shí),可能會(huì)有小數(shù),從而導(dǎo)致位置的偏差,所以我們就需要對(duì)步長(zhǎng)公式進(jìn)行取整操作,由于元素是向前運(yùn)動(dòng)(正方向),所以我們采用的策略是向上取整:
var step = Math.ceil((target - obj.offsetLeft)/10);
此時(shí)我們?cè)趤?lái)看看最終到達(dá)的目標(biāo)位置是:

此時(shí)就剛好到達(dá)了目標(biāo)位置。
五、 動(dòng)畫(huà)函數(shù)在多個(gè)目標(biāo)值之間移動(dòng)
但是如果我們的步長(zhǎng)為負(fù)呢?
舉個(gè)例子,現(xiàn)在有一個(gè)盒子,給其添加兩個(gè)按鈕,一個(gè)讓元素移動(dòng)到400px的位置,一個(gè)讓元素移動(dòng)到700px:
function animate(obj,target){
clearInterval(obj.timer)
obj.timer = setInterval(function(){
var step = Math.ceil((target - obj.offsetLeft)/10);
if(obj.offsetLeft >= target){
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + step +'px';
},30);
}
var box1 = document.querySelector('.box1');
var btn = document.querySelectorAll('button')
btn[0].addEventListener('click',function(){
animate(box1,400);
})
btn[1].addEventListener('click',function(){
animate(box1,700);
})
實(shí)現(xiàn)效果為:

此時(shí)發(fā)現(xiàn),當(dāng)我們正向運(yùn)動(dòng)的時(shí)候,元素可以精確的到達(dá)目標(biāo)位置,且元素也能實(shí)現(xiàn)在兩個(gè)像素間移動(dòng)的效果,但是向后退時(shí)達(dá)到的位置卻并不是目標(biāo)位置,這是因?yàn)槲覀兊脑卦诘雇说臅r(shí)候,是屬于反向運(yùn)動(dòng)的,這時(shí)我們也應(yīng)該讓步長(zhǎng)向反向長(zhǎng)的位置取整,即向下取整。
這時(shí),我們應(yīng)該對(duì)步長(zhǎng)條件進(jìn)行判斷,如果步長(zhǎng)大于零,則向上取整,如果步長(zhǎng)小于零,則向下取整,調(diào)整后的步長(zhǎng)公式為:
var step =(target - obj.offsetLeft)/10; step > 0 ? Math.ceil(step) : Math.floor(step);
此時(shí)再來(lái)看看效果:

問(wèn)題就解決了。
但是我們此時(shí)只是簡(jiǎn)單的實(shí)現(xiàn)了一個(gè)元素在兩個(gè)位置的移動(dòng),如果我們想要在它移動(dòng)后改變顏色,該如何操作呢?我們就可以通過(guò)給動(dòng)畫(huà)函數(shù)添加回調(diào)函數(shù) 來(lái)實(shí)現(xiàn)。
六、動(dòng)畫(huà)函數(shù)添加回調(diào)函數(shù)
回調(diào)函數(shù)原理:函數(shù)可以作為一個(gè)參數(shù)。將這個(gè)函數(shù)作為參數(shù)傳到另一個(gè)函數(shù)里面,當(dāng)那個(gè)函數(shù)執(zhí)行完之后,再執(zhí)行傳進(jìn)去的這個(gè)函數(shù),這個(gè)過(guò)程就叫做回調(diào)。
回調(diào)函數(shù)寫(xiě)的位置:定時(shí)器結(jié)束的位置。
具體實(shí)現(xiàn)代碼為:
function animate(obj,target,callback){
clearInterval(obj.timer)
obj.timer = setInterval(function(){
var step =(target - obj.offsetLeft)/10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if(obj.offsetLeft == target){
clearInterval(obj.timer);
if(callback){
callback();
}
}
obj.style.left = obj.offsetLeft + step +'px';
},30);
}
var box1 = document.querySelector('.box1');
var btn = document.querySelectorAll('button');
btn[0].addEventListener('click',function(){
animate(box1,400,function(){
box1.style.backgroundColor = 'pink';
});
})
btn[1].addEventListener('click',function(){
animate(box1,700,function(){
box1.style.backgroundColor = 'red';
});
})
實(shí)現(xiàn)效果為:

以上就是動(dòng)畫(huà)函數(shù)的封裝,在具體使用的時(shí)候,我們就可以將其封裝成一個(gè)js文件,需要的時(shí)候就可以直接引用。
?到此這篇關(guān)于JavaScript動(dòng)畫(huà)函數(shù)封裝詳解的文章就介紹到這了,更多相關(guān)JavaScript動(dòng)畫(huà)函數(shù)封裝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript實(shí)現(xiàn)LRU緩存的三種方式詳解
LRU全稱(chēng)為L(zhǎng)east?Recently?Used,即最近使用的。針對(duì)的是在有限的內(nèi)存空間內(nèi),只緩存最近使用的數(shù)據(jù)(即get和set的數(shù)據(jù))。本文介紹了JavaScript實(shí)現(xiàn)LRU緩存的三種方式,需要的可以參考一下2022-06-06
JavaScript 語(yǔ)言精粹學(xué)習(xí)筆記
JavaScript建立在一些非常好的想法和少數(shù)非常壞的想法之上。2009-08-08
JavaScript實(shí)現(xiàn)圖片懶加載的兩種方式
現(xiàn)在的科技發(fā)達(dá),圖片的資源占比越來(lái)越大,對(duì)圖片在頁(yè)面的優(yōu)化已經(jīng)成為前端開(kāi)發(fā)必備的技術(shù)之一,難的圖片懶加載方法咱們看著頭大,簡(jiǎn)單,易懂的才適合我們程序員,所以本文給大家介紹了JavaScript實(shí)現(xiàn)圖片懶加載的兩種方式,需要的朋友可以參考下2024-04-04
js對(duì)字符串和數(shù)字進(jìn)行加法運(yùn)算的一些情況
這篇文章主要介紹了js對(duì)字符串和數(shù)字進(jìn)行加法運(yùn)算的一些情況,需要的朋友可以參考下2023-02-02
使用JavaScript實(shí)現(xiàn)一個(gè)交互式待辦事項(xiàng)列表
JavaScript是一種強(qiáng)大的腳本語(yǔ)言,廣泛應(yīng)用于Web開(kāi)發(fā)中,本文將通過(guò)一個(gè)完整的項(xiàng)目實(shí)例,演示如何使用JavaScript來(lái)實(shí)現(xiàn)一個(gè)交互式的待辦事項(xiàng)列表,,需要的朋友可以參考下2023-08-08
JS控制網(wǎng)頁(yè)動(dòng)態(tài)生成任意行列數(shù)表格的方法
這篇文章主要介紹了JS控制網(wǎng)頁(yè)動(dòng)態(tài)生成任意行列數(shù)表格的方法,實(shí)例分析了javascript操作表格節(jié)點(diǎn)控制dom元素添加的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03
JavaScript實(shí)現(xiàn)多層顏色選項(xiàng)卡嵌套
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)多層顏色選項(xiàng)卡嵌套,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09
uniapp微信小程序無(wú)法獲取Vue.prototype值的解決方法
在uniapp開(kāi)發(fā)過(guò)程中,各端的一些高度會(huì)有區(qū)別,為了方便就要統(tǒng)一放到全局變量中,下面這篇文章主要給大家介紹了關(guān)于uniapp微信小程序無(wú)法獲取Vue.prototype值的解決方法,需要的朋友可以參考下2022-10-10

