JavaScript封裝簡易動(dòng)畫函數(shù)

  在學(xué)習(xí)javascript動(dòng)畫效果的過程,動(dòng)畫函數(shù)一定是少不了的,所以在初級學(xué)習(xí)的過程中钞护,封裝好一個(gè)動(dòng)畫函數(shù)可以直接調(diào)用能夠幫我們省下更多的學(xué)習(xí)時(shí)間喉祭。下面是我一步步完善動(dòng)畫函數(shù)的過程养渴。
1、簡單的右移函數(shù):鼠標(biāo)點(diǎn)擊按鈕泛烙,box向右移動(dòng)一定的位置
//封裝右移動(dòng)畫函數(shù)
        function animateMoveRight(element,target){
            //通過offsetLeft獲取當(dāng)前位置的left值
            var left = element.offsetLeft;

            //開啟定時(shí)器
            var timer = setInterval(function(){
                //當(dāng)前位置每一次+5 實(shí)現(xiàn)勻速運(yùn)動(dòng)
                left += 5;
                //將每一次改變后的left值設(shè)置給元素
                element.style.left = left + 'px';
                //判斷動(dòng)畫結(jié)束的標(biāo)志 到達(dá)目標(biāo)位置停止計(jì)時(shí)器
                if(left >= target){
                    clearInterval(timer);
                }    
            },30);
        }
        //在window.onload中調(diào)用封裝好的動(dòng)畫函數(shù)
        window.onload =function () {
            var box = document.getElementById('box');

            //動(dòng)態(tài)創(chuàng)建按鈕
            for(var i = 200; i < 1000; i += 100){
                //創(chuàng)建按鈕
                var button = document.createElement('button');            
                button.innerHTML = '右移' + i + 'px';
                //獲取按鈕對應(yīng)的移動(dòng)值
                button.index = i;
                //點(diǎn)擊按鈕
                button.onclick = function(){
                    // console.log(this.index);
                    //調(diào)用封裝好的右移函數(shù)
                    animateMoveRight(box,this.index);
                }
                //添加按鈕
                document.body.appendChild(button);
            }            
        }
    </script>

實(shí)現(xiàn)效果:


右移效果.png
2理卑、封裝同時(shí)解決左右移動(dòng)的動(dòng)畫函數(shù)

上面的函數(shù)只能實(shí)現(xiàn)單向的向右移動(dòng),點(diǎn)擊‘右移500px’按鈕后蔽氨,再點(diǎn)擊‘右移200px’按鈕無法回到200px處藐唠。下面實(shí)現(xiàn)這種效果。

//封裝一個(gè)函數(shù)  同時(shí)解決左右移動(dòng)的問題
        function animateMove(element,target){
            clearInterval(timer)
            var left = element.offsetLeft;

            //設(shè)置步長 表示一步動(dòng)作的差值
            //通過比較element當(dāng)前的left值和target值的大小鹉究,來確定平移方向
            var step = (target - left) / 10;

            var timer = setInterval(function(){
                //如果目標(biāo)值大于當(dāng)前的left值宇立,step為正數(shù),向右移動(dòng)
                //如果目標(biāo)值小于當(dāng)前的left值自赔,step為負(fù)數(shù)妈嘹,向左移動(dòng)
                left += step;
                box.style.left = left + 'px';

                //判斷停止動(dòng)畫
                //比較差值,取絕對值绍妨,當(dāng)兩者的差值小于了步進(jìn)值時(shí)润脸,停止動(dòng)畫,
                if(Math.abs(target - left) <= Math.abs(step)){
                    clearInterval(timer);
                    element.style.left = target + 'px';
                }    
            },30);
        }

        
        //調(diào)用函數(shù)
        window.onload =function () {
            var box = document.getElementById('box');
            
            for(var i = 200; i < 1000; i += 100){
                var button = document.createElement('button');    

                button.innerHTML = '右移' + i + 'px';
                button.target = i;
                button.onclick = function(){
                    animateMove(box,this.target);
                }
                document.body.appendChild(button);
            }            
        }

效果展示:(當(dāng)前在400px位置他去,點(diǎn)擊200px按鈕會(huì)回到200px位置)

左右移動(dòng).png
3津函、封裝帶有指定屬性的動(dòng)畫函數(shù)

在設(shè)置動(dòng)畫的過程中,不只是左右移動(dòng)那么簡單孤页,我們想要是的是想改變元素的什么屬性就能夠改變尔苦。在開始之前先了解怎么訪問并獲取css的屬性。

3.1 訪問css屬性

我們知道element.style.xxx 只能夠獲取行內(nèi)式屬性,無法獲取在style中設(shè)置的屬性允坚;offset獲取的是本身實(shí)際獲得的魂那,沒有定位,沒有設(shè)left夜里可以獲得稠项。我們通過設(shè)置element.currentStyle.xxx(ie瀏覽器)或者window.getComputedStyle(element, null).xxx(其他瀏覽器)獲得涯雅。封裝函數(shù)如下:

1 //封裝一個(gè)函數(shù),用于獲取某一個(gè)元素的某一條CSS屬性值
 2         function getStyle(element, styleName){
 3             if(element.currentStyle){
 4                 return element.currentStyle[styleName];
 5             }else{
 6                 var computedStyle = window.getComputedStyle(element, null);
 7                 return computedStyle[styleName];
 8             }
 9         }
10 
11         window.onload = function(){
12             var box = document.getElementById('box');
13             var height = getStyle(box,'height');
14             console.log(height); //200px
15         }
3.2 封裝帶有指定屬性的動(dòng)畫函數(shù)
//引入getStyle函數(shù)
        function getStyle(element, styleName){
            if(element.currentStyle){
                return element.currentStyle[styleName];
            }else{
                var computedStyle = window.getComputedStyle(element, null);
                return computedStyle[styleName];
            }
        }

        //封裝帶有指定屬性的的動(dòng)畫函數(shù) (元素名,屬性名展运,目標(biāo)值)
        var timer;
        function animate(element,styleName,target){
            clearInterval(timer);
            //獲取該元素當(dāng)前的屬性
            var current = parseInt(getStyle(element,styleName));
            //設(shè)置步長 定值
            var step = (target - current) / 10;
            
            //開啟動(dòng)畫設(shè)置滾動(dòng)效果移動(dòng) 
            timer = setInterval(function(){
                //通過步長 一點(diǎn)的的改變current  直到達(dá)到target值
                current += step;
                //判斷動(dòng)畫結(jié)束的標(biāo)志 
                //比較差值 當(dāng)兩者的差值小于了步進(jìn)值時(shí)活逆,停止動(dòng)畫 
                if(Math.abs(target - current) <= Math.abs(step)){
                    clearInterval(element.timer);
                    current = target;  //存在一點(diǎn)誤差 強(qiáng)制將current歸為目標(biāo)值
                }

                //將改變后當(dāng)前動(dòng)畫中的style值,設(shè)置給動(dòng)畫的元素
                element.style[styleName] = current + 'px';
            },30);
        }

        //調(diào)用
        window.onload = function(){
            var box =document.getElementById('box');
            
            animate(box,'width',500);
        } 
4拗胜、封裝帶有多個(gè)屬性的動(dòng)畫函數(shù)(同時(shí)運(yùn)動(dòng))

前面雖然能根據(jù)傳入的屬性參數(shù)改變元素運(yùn)動(dòng)蔗候,但是每次只能設(shè)置一種屬性,如果同時(shí)調(diào)用只會(huì)顯示最后一種效果埂软。所以下面使用json參數(shù)傳入多個(gè)屬性锈遥。

 <script type="text/javascript">
    //json格式參考
    function f(){
        var json ={left:100,top:50}
        for(var key in json){
            console.log(key); //打印屬性 left top
            console.log(json[key]); //打印屬性值 100  50
        }
    }
    f();
    </script>
//獲取屬性的的網(wǎng)頁中實(shí)際的(當(dāng)前的)屬性值
        function getStyle(element, styleName){
            if(element.currentStyle){
                return element.currentStyle[styleName];
            }else{
                var computedStyle = window.getComputedStyle(element, null);
                return computedStyle[styleName];
            }
        }

        //封裝帶有多個(gè)屬性的的動(dòng)畫函數(shù)    利用json參數(shù)
        function animate(element,json){
            clearInterval(element.timer);
            //由于多個(gè)屬性的運(yùn)動(dòng)  為了避免一個(gè)屬性完成后就停止定時(shí)器的現(xiàn)象,所以設(shè)置isStop
            //是否停止動(dòng)畫,默認(rèn)為false表示不停止
            var isStop = false;

            //開啟動(dòng)畫設(shè)置滾動(dòng)效果移動(dòng) 
            element.timer = setInterval(function(){

                //1.每一次動(dòng)畫開啟之前,默認(rèn)設(shè)置isStop為true(定時(shí)器停止)
                //2.如果只是一個(gè)屬性完成不需要修改定時(shí)器,如果有屬性沒有    執(zhí)行完,則設(shè)置isStop = false,繼續(xù)開啟定時(shí)器
                //3.最后所有屬性都完成后, 判斷isStop值     如果為true,表示的屬性均執(zhí)行完成,關(guān)閉定時(shí)器
                //1.
                isStop = true;

                //多個(gè)屬性  分別計(jì)算每個(gè)屬性當(dāng)前值(實(shí)際值)/目標(biāo)值/步長
                //遍歷json參數(shù)  分別獲取key-屬性名 json[key]-屬性值
                for(var key in json){
                    console.log(key);        //left top
                    console.log(json[key]);  // 100 50

                    //通過getStyle函數(shù)獲取當(dāng)前屬性(key)的屬性值即盒子的當(dāng)前實(shí)際值
                    var current = parseInt(getStyle(element, key));
                    //獲取json參數(shù)傳入的每個(gè)屬性對應(yīng)的目標(biāo)值
                    var target = json[key];
                    //分別設(shè)置每個(gè)屬性步長
                    var step = (target - current) / 10;
                    step = step > 0 ? Math.ceil(step) : Math.floor(step);

                    //設(shè)置一步步的改變 直至達(dá)到目標(biāo)值
                    current += step;

                    //判斷(current += step)是否達(dá)到目標(biāo)值 停止計(jì)時(shí)器
                    //2.其中一個(gè)屬性完成,就不需要修改定時(shí)器
                    if(Math.abs(target -current) > Math.abs(step)){
                        isStop = false;
                    }else{ //強(qiáng)制將此屬性設(shè)到target
                        current = target;
                    }

                    //設(shè)置運(yùn)動(dòng)后的值給元素, 改變其對應(yīng)屬性的屬性值
                    element.style[key] = current + 'px';    
                }

                //3.所有的屬性動(dòng)畫完成(for(key)結(jié)束),所有的定時(shí)器都為true,關(guān)閉定時(shí)器
                if(isStop){
                    clearInterval(element.timer);
                    console.log('完成動(dòng)畫');
                }
            },30);
        }
        //調(diào)用此函數(shù)
        window.onload = function(){
            var box =document.getElementById('box');
            document.onclick =function(){
                //實(shí)現(xiàn)點(diǎn)擊后勘畔,在一定時(shí)間內(nèi)同時(shí)完成以下動(dòng)作
                animate(box,{
                    left:200,
                    top :200,
                    width:300,
                    height:300
                });
            }
        }

實(shí)現(xiàn)效果:鼠標(biāo)點(diǎn)擊后所灸,在一定時(shí)間內(nèi)盒子同時(shí)向左向下移動(dòng)200px,并且寬高擴(kuò)大到300px炫七。

5爬立、函數(shù)的回歸調(diào)用(上一個(gè)動(dòng)畫運(yùn)動(dòng)完成后下一個(gè)動(dòng)畫才開始運(yùn)動(dòng))

上面的代碼實(shí)現(xiàn)了一個(gè)物體的多個(gè)屬性同時(shí)運(yùn)動(dòng),很多情況下會(huì)是一個(gè)物體的上一個(gè)動(dòng)畫完成后另一個(gè)動(dòng)畫才開始運(yùn)動(dòng)万哪。所以我們在原來的基礎(chǔ)上傳入一個(gè)函數(shù)參數(shù)侠驯,function animate(element,json,fun){},在上一個(gè)動(dòng)畫完成后壤圃,開始調(diào)用下一個(gè)動(dòng)畫的函數(shù)參數(shù)陵霉。

  //回調(diào)函數(shù)
        function animate(element,json,fun){
            clearInterval(element.timer);
            console.log(element.offsetLeft + 'kaishiqian')
            var isStop = false;

            element.timer = setInterval(function(){

                isStop = true;

                for(var key in json){
                    console.log(key);        //left top
                    console.log(json[key]);  // 100 50
                    var current = parseInt(getStyle(element, key));
                    var target = json[key];
                    var step = (target - current) / 10;
                    step = step > 0 ? Math.ceil(step) : Math.floor(step);
                    current += step;

                    if(Math.abs(target -current) > Math.abs(step)){
                        isStop = false;
                    }else{ //強(qiáng)制將此屬性設(shè)到target
                        current = target;
                    }
                    element.style[key] = current + 'px';    
                }

                if(isStop){
                    clearInterval(element.timer);
                    console.log('完成動(dòng)畫');
                    console.log(element.offsetLeft);

                    //上一個(gè)動(dòng)畫完成后琅轧,開始下一個(gè)動(dòng)畫
                    if(typeof fun == 'function'){
                        fun();
                    }
                }
            },30);
        }

        window.onload = function(){
            var box =document.getElementById('box');
            document.onclick =function(){
                //先向右移動(dòng)到500px,接著寬高均擴(kuò)大到300px,下移到150px,字體放大到30px
                animate(box,{left:500}, function(){
                    animate(box,{width:300, height:300}, function(){
                        animate(box,{top:150}, function(){
                            animate(box,{fontSize:30}, null);
                        });
                    });
                });
            }
        }

實(shí)現(xiàn)效果:鼠標(biāo)點(diǎn)擊后伍绳,盒子先向右移動(dòng)到500px,接著寬高均擴(kuò)大到300px,下移到150px,字體放大到30px。

6乍桂、封裝帶有opacity冲杀、z-index等屬性的動(dòng)畫函數(shù)
//思路:即查看current,target,step的值是否會(huì)因?yàn)閛pacity的傳入而出錯(cuò)
        function animate(element,json,fun){
            clearInterval(element.timer);
            console.log(element.offsetLeft + 'kaishiqian')
            var isStop = false;

            element.timer = setInterval(function(){

                isStop = true;

                for(var key in json){

                    var current;
                    //如果傳入的屬性是opacity,取浮點(diǎn)型數(shù)
                    if(key == 'opacity'){
                        current = parseFloat(getStyle(element, key));
                    }else{
                        current = parseInt(getStyle(element, key));
                    }

                    //沒問題
                    var target = json[key];

                    //只要不是opacity 都做向上或向下取整操作
                    var step = (target - current) / 10;
                    if(key != 'opacity'){
                        step = step > 0 ? Math.ceil(step) : Math.floor(step);
                    }

                    current += step;

                    //判斷暫停動(dòng)畫
                    if(key == 'opacity'){

                        if(Math.abs(target -current) > 0.01){
                            isStop = false;
                        }else{ 
                            current = target;
                        }
                        element.style[key] = current + '';

                    }else{

                        if(Math.abs(target -current) > Math.abs(step)){
                            isStop = false;
                        }else{ //強(qiáng)制將此屬性設(shè)到target
                            current = target;
                        }
                        
                        if(key == 'zIndex'){
                            //四舍五入
                            element.style.zIndex = Math.round(current);
                        }else{
                            element.style[key] = current + 'px';    
                        }
                        
                    }
                }
                if(isStop){
                    clearInterval(element.timer);
                    console.log('完成動(dòng)畫');
                    if(typeof fun == 'function'){
                        fun();
                    }
                }
            },30);
        }

        window.onload = function(){
            var box =document.getElementById('box');
            document.onclick =function(){

                animate(box, {opacity:0.3,zIndex:20}, null);
            }
        }

實(shí)現(xiàn)效果:透明度由1 變?yōu)?.3 睹酌,z-index由10 變?yōu)?0权谁。

到這里一個(gè)較為完善的動(dòng)畫函數(shù)就封裝完成了。

如有任何疑問請留言憋沿。

接下將介紹幾種通過js動(dòng)畫效果實(shí)現(xiàn)各式輪播圖的案例......

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末旺芽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌采章,老刑警劉巖运嗜,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異悯舟,居然都是意外死亡担租,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門抵怎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奋救,“玉大人,你說我怎么就攤上這事反惕〕⑺遥” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵承璃,是天一觀的道長利耍。 經(jīng)常有香客問我,道長盔粹,這世上最難降的妖魔是什么隘梨? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮舷嗡,結(jié)果婚禮上轴猎,老公的妹妹穿的比我還像新娘。我一直安慰自己进萄,他們只是感情好捻脖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著中鼠,像睡著了一般可婶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上援雇,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天矛渴,我揣著相機(jī)與錄音,去河邊找鬼惫搏。 笑死具温,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的筐赔。 我是一名探鬼主播铣猩,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼茴丰!你這毒婦竟也來了达皿?” 一聲冷哼從身側(cè)響起天吓,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎峦椰,沒想到半個(gè)月后失仁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡们何,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年萄焦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冤竹。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拂封,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鹦蠕,到底是詐尸還是另有隱情冒签,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布钟病,位于F島的核電站萧恕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏肠阱。R本人自食惡果不足惜票唆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望屹徘。 院中可真熱鬧走趋,春花似錦、人聲如沸噪伊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鉴吹。三九已至姨伟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間豆励,已是汗流浹背夺荒。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肆糕,地道東北人般堆。 一個(gè)月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓在孝,卻偏偏與公主長得像诚啃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子私沮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,102評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫始赎、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,102評論 4 62
  • ˙?˙ ? ?? ? ?????? ′? ? `? ?_? (-?_-?) ??...
    邢月婷閱讀 9,782評論 0 1
  • O:早上晨會(huì),領(lǐng)導(dǎo)分享了柯達(dá)的故事: 柯達(dá)之前是行業(yè)的巨霸造垛,由于膠卷利潤率太可觀等一些原因魔招,高層把新技術(shù)隱藏起來,...
    海洋里的小彩魚閱讀 177評論 0 0
  • 感冒發(fā)燒鼻塞咳嗽簡直就是這個(gè)季節(jié)的常態(tài)五辽。雖然我們都知道這些問題不大办斑,很快就會(huì)好;雖然我們都懂小朋友就是這樣漸漸有了...
    小北北媽閱讀 794評論 3 7