JavaScript封裝減速運動框架

假設(shè)需要實現(xiàn)一個div 盒子的寬高減速運動變化過渡梦重,首先要思考的問題就是,現(xiàn)在div盒子的寬高是多少亮瓷?要變化到多少琴拧?

首先需要解決的問題,需要獲取用戶輸入對象的當(dāng)前css屬性值寺庄,其次JavaScript要實現(xiàn)減速運動艾蓝,運動變化到多少需要使用定時器來把運動拆分成不同時間段的具體變化,從而實現(xiàn)動畫的過渡斗塘。下面來詳細(xì)講解JavaScript如何實現(xiàn)減速運動赢织。

不同的瀏覽器獲取css屬性值的寫法不一樣,所以要書寫判斷馍盟。IE和Opera瀏覽器支持的寫法是obj.currentStyle[attr]于置,其他w3c支持的瀏覽器支持的寫法是getComputedStyle(obj,null)[attr]。

以下是封裝獲取div元素的css屬性值的代碼:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            
            #box{width: 200px; height: 300px; background:tan; position: absolute; left: 0;}
                        
        </style>
    </head>
    <body>
        
        
        <button id="btn1">按鈕1</button>
        <button id="btn2">按鈕2</button>
        
        <div id="box"></div>
        
        <script>
            
            var btn1 = document.getElementById("btn1");
            var btn2 = document.getElementById("btn2");
            var box = document.getElementById("box");
            
            //封裝獲取用戶輸入對象對應(yīng)css屬性值函數(shù)
            function getStyle(obj,attr){
                //如果obj存在currentStyle
                if(obj.currentStyle){
                    //IE Opera瀏覽器
                    //返回對象屬性值
                    return obj.currentStyle[attr];
                }else{
                    //w3c支持的瀏覽器
                    return getComputedStyle(obj,null)[attr];
                }
            }
            
            //這里輸出盒子的高度300px
            //console.log(getStyle(box,"height"));
            
        </script>       
    </body>
</html>

現(xiàn)在已經(jīng)可以得到用戶輸入屬性對應(yīng)的css屬性值贞岭,下面來講解如何實現(xiàn)動畫八毯。

首先需要理解減速運動的公式搓侄,減速運動在于每次的運動的步長越來越小,需要在循環(huán)定時器內(nèi)計算每次運動的步長。

步長 = (目標(biāo)值 - 當(dāng)前值)/ 步數(shù)

在循環(huán)定時器內(nèi)部话速,當(dāng)前值是不斷獲取不斷變化的讶踪,并且越來越接近目標(biāo)值,而對象的css屬性值也需要不斷變化泊交。

對象的css屬性值 = 當(dāng)前值 + 步長

目標(biāo)值是用戶輸入的屬性最終的值乳讥,而用戶輸入的最終值可能是多個屬性,所以最終值應(yīng)該是一個json數(shù)據(jù)廓俭,多個屬性操作則需要對json數(shù)據(jù)進(jìn)行遍歷云石。當(dāng)前值則需要在定時器內(nèi)不斷的獲取。

實現(xiàn)代碼和詳細(xì)注釋:

<script>
            
            var btn1 = document.getElementById("btn1");
            var btn2 = document.getElementById("btn2");
            var box = document.getElementById("box");
            
            //封裝獲取用戶輸入對象對應(yīng)css屬性值函數(shù)
            function animate(obj,json){

                setInterval(function(){
                    //遍歷用戶輸入屬性json數(shù)據(jù)
                    for(k in json){
                        //k是用戶輸入屬性
                        //json[k]是對應(yīng)屬性的值
                        //console.log(json[k]);
                        //獲取對象當(dāng)前css屬性值研乒,獲取的是字符型汹忠,需要轉(zhuǎn)化成數(shù)字
                        var curStyle = parseInt(getStyle(obj,k));
                        
                        //得到步長
                        //步長 = (最終值 - 當(dāng)前值)/ 步數(shù);
                        var step = (json[k] - curStyle) / 10;
                        
                        //控制臺輸出能看到步長不斷減小
                        //console.log(step)
                        
                        //對象的css屬性值 = 當(dāng)前值 + 步長雹熬;
                        obj.style[k] = curStyle + step + "px";
                        
                    }
                                
                },10)
                
            }
            
            //點擊btn1能看到box寬高動畫變化
            btn1.onclick = function(){
                animate(box,{width:400,height:600});    
            }

</script>

如下圖所示宽菜,點擊btn1已經(jīng)可以實現(xiàn)盒子寬高的減速動畫變化過渡。

減速動畫變化

前面步驟雖然已經(jīng)可以實現(xiàn)盒子動畫減速過渡變化橄唬,但是審查元素發(fā)現(xiàn)盒子最終寬高并不等于用戶輸入的數(shù)值赋焕。如下圖所示:

審查元素

原因是因為瀏覽器最小只能識別1px,但是步長step在除以步數(shù)的過程中仰楚,會出現(xiàn)除不盡的小數(shù)情況隆判。所以在這里步長要作一個取整處理。如果步長是正數(shù)則向上取整僧界,否則向下取整侨嘀。

Math.ceil()向上取整,取比該數(shù)值大的整數(shù)
Math.floor()向下取整捂襟,取比該數(shù)值小的整數(shù)

步長加上以下判斷賦值則可以解決這個問題咬腕。

step = step>0?Math.ceil(step):Math.floor(step);

上面已經(jīng)可以實現(xiàn)盒子寬高減速運動變化,那么什么時候停止定時器呢葬荷?

所有用戶輸入的css屬性都完成動畫變化過渡則可以停止定時器涨共。

在遍歷外聲明兩個變量來記錄屬性變化,聲明num記錄屬性總個數(shù),聲明key來記錄已經(jīng)完成變化屬性的個數(shù)宠漩。遍歷前兩個變量的值都先設(shè)置為0举反。

屬性總個數(shù)num遍歷一次增加一個num++,已經(jīng)完成變化屬性個數(shù)key扒吁,變化完成一個增加一個 key++火鼻,怎么判斷屬性是否變化完成?如果當(dāng)前值 = 目標(biāo)值,該屬性就變化完成魁索。

下面代碼把定時器賦給了對象obj的timer屬性融撞,如果需要調(diào)整運動速度可以通過修改定時器的間隔時間或者步數(shù)。

以下代碼包含詳細(xì)注釋:

<script>
            
            var btn1 = document.getElementById("btn1");
            var btn2 = document.getElementById("btn2");
            var box = document.getElementById("box");
            
            //封裝獲取用戶輸入對象對應(yīng)css屬性值函數(shù)
            function getStyle(obj,attr){
                //如果obj存在currentStyle
                if(obj.currentStyle){
                    //IE Opera瀏覽器
                    //返回對象屬性值
                    return obj.currentStyle[attr];
                }else{
                    //w3c支持的瀏覽器
                    return getComputedStyle(obj,null)[attr];
                }
            }
            
            //這里輸出盒子的高度300px
            //console.log(getStyle(box,"height"));
            
            //封裝緩動動畫函數(shù)
            function animate(obj,json){
                
                //為了優(yōu)化效率粗蔚,開啟定時器前先清除定時器
                clearInterval(obj.timer);
                
                obj.timer = setInterval(function(){
                    
                    //在遍歷外記錄屬性個數(shù)尝偎,初始都定義為0
                    var num = 0;    //記錄總個數(shù)
                    var key = 0;//記錄已達(dá)到屬性的個數(shù)
                    
                    //遍歷用戶輸入屬性json數(shù)據(jù)
                    for(k in json){
                        //k是用戶輸入屬性
                        //json[k]是對應(yīng)屬性的值
                        //console.log(json[k]);
                        //獲取對象當(dāng)前css屬性值,獲取的是字符型,需要轉(zhuǎn)化成數(shù)字
                        var curStyle = parseInt(getStyle(obj,k));
                        
                        //得到步長
                        //步長 = (最終值 - 當(dāng)前值)/ 步數(shù)鹏控;
                        var step = (json[k] - curStyle) / 10;
                        
                        //控制臺能看到步長不斷減小
                        //console.log(step)
                        
                        //Math.ceil()向上取整冬念,取比該數(shù)值大的整數(shù)
                        //Math.floor()向下取整,取比該數(shù)值小的整數(shù)
                        //步長判斷取整后重新賦值
                        step = step>0?Math.ceil(step):Math.floor(step);
                        
                        //對象的css屬性值 = 當(dāng)前值 + 步長牧挣;
                        obj.style[k] = curStyle + step + "px";
                        
                        //屬性總個數(shù)遍歷一次增加一個
                        num++;
                        
                        //如果當(dāng)前值等于用戶輸入的值,則已經(jīng)完成一個屬性的變化
                        if(curStyle == json[k]){
                            //key記錄的是已經(jīng)完成變化的屬性數(shù)醒陆,到達(dá)一個增加一個key++
                            key ++;
                        }
                                        
                        
                    }
                                    
                    //在遍歷外面判斷到達(dá)屬性的個數(shù)是否等于遍歷屬性的總個數(shù)                
                    if(key == num){
                        //如果兩個相等瀑构,表示所有屬性變化完成,則停止定時器
                        clearInterval(obj.timer)
                    }
                    
                    //console.log(num)
                    //console.log(key)          
                    
                },30)
                
            }
            
            //點擊btn1能看到box屬性動畫變化
            btn1.onclick = function(){
                animate(box,{width:1200,height:400,marginTop:100}); 
            }
            
            //點擊btn2能看到box屬性動畫變化
            btn2.onclick = function(){
                animate(box,{width:200,height:200,marginTop:0});    
            }

                        
        </script>   

點擊按鈕效果刨摩,如下圖所示:

點擊按鈕效果

到這一步寺晌,已經(jīng)完成了減速運動變化框架封裝。

最后一步來進(jìn)行優(yōu)化澡刹,為減速運動框架添加回調(diào)函數(shù)呻征。

所謂回調(diào)函數(shù)是指在動畫運動完成后執(zhí)行的函數(shù)。需要給animate函數(shù)添加一個參數(shù)fn接收回調(diào)函數(shù)罢浇,如果用戶有傳回調(diào)函數(shù)陆赋,運動完成后就執(zhí)行這個函數(shù),所以是在停止定時器后再進(jìn)行判斷和調(diào)用fn嚷闭。

下面為減速運動框架封裝最終代碼:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            
            #box{width: 200px; height: 300px; background:tan; position: absolute; left: 0;}
                        
        </style>
    </head>
    <body>
        
        
        <button id="btn1">按鈕1</button>
        <button id="btn2">按鈕2</button>
        
        <div id="box"></div>
        
        <script>
            
            var btn1 = document.getElementById("btn1");
            var btn2 = document.getElementById("btn2");
            var box = document.getElementById("box");
            
            //封裝獲取用戶輸入對象對應(yīng)css屬性值函數(shù)
            function getStyle(obj,attr){
                //如果obj存在currentStyle
                if(obj.currentStyle){
                    //IE Opera瀏覽器
                    //返回對象屬性值
                    return obj.currentStyle[attr];
                }else{
                    //w3c支持的瀏覽器
                    return getComputedStyle(obj,null)[attr];
                }
            }
            
            //這里輸出盒子的高度300px
            //console.log(getStyle(box,"height"));
            
            //封裝緩動動畫函數(shù)
            function animate(obj,json,fn){
                
                //為了優(yōu)化效率攒岛,開啟定時器前先清除定時器
                clearInterval(obj.timer);
                
                obj.timer = setInterval(function(){
                    
                    //在遍歷外記錄屬性個數(shù),初始都定義為0
                    var num = 0;    //記錄總個數(shù)
                    var key = 0;//記錄已達(dá)到屬性的個數(shù)
                    
                    //遍歷用戶輸入屬性json數(shù)據(jù)
                    for(k in json){
                        //k是用戶輸入屬性
                        //json[k]是對應(yīng)屬性的值
                        //console.log(json[k]);
                        //獲取對象當(dāng)前css屬性值,獲取的是字符型胞锰,需要轉(zhuǎn)化成數(shù)字
                        var curStyle = parseInt(getStyle(obj,k));
                        
                        //得到步長
                        //步長 = (最終值 - 當(dāng)前值)/ 步數(shù)灾锯;
                        var step = (json[k] - curStyle) / 10;
                        
                        //控制臺能看到步長不斷減小
                        //console.log(step)
                        
                        //Math.ceil()向上取整,取比該數(shù)值大的整數(shù)
                        //Math.floor()向下取整嗅榕,取比該數(shù)值小的整數(shù)
                        //步長判斷取整后重新賦值
                        step = step>0?Math.ceil(step):Math.floor(step);
                        
                        //對象的css屬性值 = 當(dāng)前值 + 步長顺饮;
                        obj.style[k] = curStyle + step + "px";
                        
                        //屬性總個數(shù)遍歷一次增加一個
                        num++;
                        
                        //如果當(dāng)前值等于用戶輸入的值,則已經(jīng)完成一個屬性的變化
                        if(curStyle == json[k]){
                            //key記錄的是已經(jīng)完成變化的屬性數(shù)凌那,到達(dá)一個增加一個key++
                            key ++;
                        }                                   
                        
                    }
                                    
                    //在遍歷外面判斷到達(dá)屬性的個數(shù)是否等于遍歷屬性的總個數(shù)                
                    if(key == num){
                        //如果兩個相等兼雄,表示所有屬性變化完成,則停止定時器
                        clearInterval(obj.timer);
                        //如果存在就調(diào)用
                        //if(fn){
                            //fn();
                        //}
                        //化簡寫法
                        fn&&fn();
                    }
                    
                    //console.log(num)
                    //console.log(key)          
                    
                },20)
                
            }
            
            //點擊btn1能看到box屬性動畫變化
            btn1.onclick = function(){
                animate(box,{width:1200,height:400,marginTop:100},function(){
                    alert("按鈕1運動完成案怯!")
                });
            }
            
            //點擊btn2能看到box屬性動畫變化
            btn2.onclick = function(){
                animate(box,{width:200,height:200,marginTop:0});    
            }
                        
        </script>
        
    </body>
</html>

注意這個減速運動框架只適用于屬性值為正整數(shù)的屬性君旦,屬性值為小數(shù)例如opacity和屬性值非數(shù)字的屬性暫不支持。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市金砍,隨后出現(xiàn)的幾起案子局蚀,更是在濱河造成了極大的恐慌,老刑警劉巖恕稠,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件琅绅,死亡現(xiàn)場離奇詭異,居然都是意外死亡鹅巍,警方通過查閱死者的電腦和手機千扶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來骆捧,“玉大人澎羞,你說我怎么就攤上這事×参” “怎么了妆绞?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長枫攀。 經(jīng)常有香客問我括饶,道長,這世上最難降的妖魔是什么来涨? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任图焰,我火速辦了婚禮,結(jié)果婚禮上蹦掐,老公的妹妹穿的比我還像新娘技羔。我一直安慰自己,他們只是感情好卧抗,可當(dāng)我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布堕阔。 她就那樣靜靜地躺著,像睡著了一般颗味。 火紅的嫁衣襯著肌膚如雪超陆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天浦马,我揣著相機與錄音时呀,去河邊找鬼。 笑死晶默,一個胖子當(dāng)著我的面吹牛谨娜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播磺陡,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼趴梢,長吁一口氣:“原來是場噩夢啊……” “哼漠畜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起坞靶,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤憔狞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后彰阴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘾敢,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年尿这,在試婚紗的時候發(fā)現(xiàn)自己被綠了簇抵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡射众,死狀恐怖碟摆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情叨橱,我是刑警寧澤焦履,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站雏逾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏郑临。R本人自食惡果不足惜栖博,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望厢洞。 院中可真熱鬧仇让,春花似錦、人聲如沸躺翻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽公你。三九已至踊淳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間陕靠,已是汗流浹背迂尝。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留剪芥,地道東北人垄开。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像税肪,于是被迫代替她去往敵國和親溉躲。 傳聞我的和親對象是個殘疾皇子榜田,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,573評論 2 359

推薦閱讀更多精彩內(nèi)容

  • HTML 5 HTML5概述 因特網(wǎng)上的信息是以網(wǎng)頁的形式展示給用戶的,因此網(wǎng)頁是網(wǎng)絡(luò)信息傳遞的載體锻梳。網(wǎng)頁文件是用...
    阿啊阿吖丁閱讀 3,906評論 0 0
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5箭券? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 27,513評論 1 45
  • 15、正則 正則就是一個規(guī)則,用來處理字符串的規(guī)則1但指、正則匹配編寫一個規(guī)則成艘,驗證某個字符串是否符合這個規(guī)則,正則匹...
    萌妹撒閱讀 1,448評論 0 1
  • JavaScript 將字符串轉(zhuǎn)換為數(shù)字 parseInt() ◆只保留數(shù)字的整數(shù)部分丰榴,不會進(jìn)行四舍五入運算。 ...
    AkaTBS閱讀 988評論 0 9
  • JS基礎(chǔ) 頁面由三部分組成:html:超文本標(biāo)記語言,負(fù)責(zé)頁面結(jié)構(gòu)css:層疊樣式表滔以,負(fù)責(zé)頁面樣式j(luò)s:輕量級的腳...
    小賢筆記閱讀 610評論 0 5