1. 程式人生 > >封裝簡單動畫函式-由簡到完善

封裝簡單動畫函式-由簡到完善

  在學習javascript動畫效果的過程,動畫函式一定是少不了的,所以在初級學習的過程中,封裝好一個動畫函式可以直接呼叫能夠幫我們省下更多的學習時間。下面是我一步步完善動畫函式的過程。

  1、簡單的右移函式:滑鼠點選按鈕,box向右移動一定的位置

//封裝右移動畫函式
        function animateMoveRight(element,target){
            //通過offsetLeft獲取當前位置的left值
            var left = element.offsetLeft;

            //開啟定時器
            var timer = setInterval(function
(){ //當前位置每一次+5 實現勻速運動 left += 5; //將每一次改變後的left值設定給元素 element.style.left = left + 'px'; //判斷動畫結束的標誌 到達目標位置停止計時器 if(left >= target){ clearInterval(timer); } },
30); } //在window.onload中呼叫封裝好的動畫函式 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.index = i; //點選按鈕 button.onclick = function(){ // console.log(this.index); //呼叫封裝好的右移函式 animateMoveRight(box,this.index); } //新增按鈕 document.body.appendChild(button); } } </script>

實現效果:

  2、封裝同時解決左右移動的動畫函式

  上面的函式只能實現單向的向右移動,點選‘右移500px’按鈕後,再點選‘右移200px’無法回到200px處。下面實現這種效果。

//封裝一個函式  同時解決左右移動的問題
        function animateMove(element,target){
            clearInterval(timer)
            var left = element.offsetLeft;

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

            var timer = setInterval(function(){
                //如果目標值大於當前的left值,step為正數,向右移動
                //如果目標值小於當前的left值,step為負數,向左移動
                left += step;
                box.style.left = left + 'px';

                //判斷停止動畫
                //比較差值,取絕對值,當兩者的差值小於了步進值時,停止動畫,
                if(Math.abs(target - left) <= Math.abs(step)){
                    clearInterval(timer);
                    element.style.left = target + 'px';
                }    
            },30);
        }

        
        //呼叫函式
        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);
            }            
        }

效果展示:(當前在400px位置,點選200px按鈕會回到200px位置)

  3、封裝帶有指定屬性的動畫函式

在設定動畫的過程中,不只是左右移動那麼簡單,我們想要是的是想改變元素的什麼屬性就能夠改變。在開始之前先了解怎麼訪問並獲取css的屬性。

    3.1 訪問css屬性

我們知道element.style.xxx 只能夠獲取行內式屬性,無法獲取在style中設定的屬性;offset獲取的是本身實際獲得的,沒有定位,沒有設left夜裡可以獲得。我們通過設定element.currentStyle.xxx(ie瀏覽器)或者window.getComputedStyle(element, null).xxx(其他瀏覽器)獲得。封裝函式如下:

 1 //封裝一個函式,用於獲取某一個元素的某一條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 封裝帶有指定屬性的動畫函式  

//引入getStyle函式
        function getStyle(element, styleName){
            if(element.currentStyle){
                return element.currentStyle[styleName];
            }else{
                var computedStyle = window.getComputedStyle(element, null);
                return computedStyle[styleName];
            }
        }

        //封裝帶有指定屬性的的動畫函式 (元素名,屬性名,目標值)
        var timer;
        function animate(element,styleName,target){
            clearInterval(timer);
            //獲取該元素當前的屬性
            var current = parseInt(getStyle(element,styleName));
            //設定步長 定值
            var step = (target - current) / 10;
            
            //開啟動畫設定滾動效果移動 
            timer = setInterval(function(){
                //通過步長 一點的的改變current  直到達到target值
                current += step;
                //判斷動畫結束的標誌 
                //比較差值 當兩者的差值小於了步進值時,停止動畫 
                if(Math.abs(target - current) <= Math.abs(step)){
                    clearInterval(element.timer);
                    current = target;  //存在一點誤差 強制將current歸為目標值
                }

                //將改變後當前動畫中的style值,設定給動畫的元素
                element.style[styleName] = current + 'px';
            },30);
        }

        //呼叫
        window.onload = function(){
            var box =document.getElementById('box');
            
            animate(box,'width',500);
        } 

 4、封裝帶有多個屬性的動畫函式(同時運動)

   前面雖然能根據傳入的屬性引數改變元素運動,但是每次只能設定一種屬性,如果同時呼叫只會顯示最後一種效果。所以下面使用json引數傳入多個屬性。

    <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>


        //獲取屬性的的網頁中實際的(當前的)屬性值
        function getStyle(element, styleName){
            if(element.currentStyle){
                return element.currentStyle[styleName];
            }else{
                var computedStyle = window.getComputedStyle(element, null);
                return computedStyle[styleName];
            }
        }

        //封裝帶有多個屬性的的動畫函式    利用json引數
        function animate(element,json){
            clearInterval(element.timer);
            //由於多個屬性的運動  為了避免一個屬性完成後就停止定時器的現象,所以設定isStop
            //是否停止動畫,預設為false表示不停止
            var isStop = false;

            //開啟動畫設定滾動效果移動 
            element.timer = setInterval(function(){

                //1.每一次動畫開啟之前,預設設定isStop為true(定時器停止)
                //2.如果只是一個屬性完成不需要修改定時器,如果有屬性沒有    執行完,則設定isStop = false,繼續開啟定時器
                //3.最後所有屬性都完成後, 判斷isStop值     如果為true,表示的屬性均執行完成,關閉定時器
                //1.
                isStop = true;

                //多個屬性  分別計算每個屬性當前值(實際值)/目標值/步長
                //遍歷json引數  分別獲取key-屬性名 json[key]-屬性值
                for(var key in json){
                    console.log(key);        //left top
                    console.log(json[key]);  // 100 50

                    //通過getStyle函式獲取當前屬性(key)的屬性值即盒子的當前實際值
                    var current = parseInt(getStyle(element, key));
                    //獲取json引數傳入的每個屬性對應的目標值
                    var target = json[key];
                    //分別設定每個屬性步長
                    var step = (target - current) / 10;
                    step = step > 0 ? Math.ceil(step) : Math.floor(step);

                    //設定一步步的改變 直至達到目標值
                    current += step;

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

                    //設定運動後的值給元素, 改變其對應屬性的屬性值
                    element.style[key] = current + 'px';    
                }

                //3.所有的屬性動畫完成(for(key)結束),所有的定時器都為true,關閉定時器
                if(isStop){
                    clearInterval(element.timer);
                    console.log('完成動畫');
                }
            },30);
        }
        //呼叫此函式
        window.onload = function(){
            var box =document.getElementById('box');
            document.onclick =function(){
                //實現點選後,在一定時間內同時完成以下動作
                animate(box,{
                    left:200,
                    top :200,
                    width:300,
                    height:300
                });
            }
        }

實現效果:滑鼠點選後,在一定時間內盒子同時向左向下移動200px,並且寬高擴大到300px。

  5、函式的迴歸呼叫(上一個動畫運動完成後下一個動畫才開始運動)

上面的程式碼實現了一個物體的多個屬性同時運動,很多情況下會是一個物體的上一個動畫完成後另一個動畫才開始運動。所以我們在原來的基礎上傳入一個函式引數,function animate(element,json,fun){},在上一個動畫完成後,開始呼叫下一個動畫的函式引數。

        //回撥函式
        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{ //強制將此屬性設到target
                        current = target;
                    }
                    element.style[key] = current + 'px';    
                }

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

                    //上一個動畫完成後,開始下一個動畫
                    if(typeof fun == 'function'){
                        fun();
                    }
                }
            },30);
        }

        window.onload = function(){
            var box =document.getElementById('box');
            document.onclick =function(){
                //先向右移動到500px,接著寬高均擴大到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);
                        });
                    });
                });
            }
        }

實現效果:滑鼠點選後,盒子先向右移動到500px,接著寬高均擴大到300px,下移到150px,字型放大到30px。

  6、封裝帶有opacity、z-index等屬性的動畫函式

前面的封裝函式傳入的屬性都是帶有px的,像opacity、z-index等不帶px單位的屬性怎麼辦?

        //思路:即檢視current,target,step的值是否會因為opacity的傳入而出錯
        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,取浮點型數
                    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;

                    //判斷暫停動畫
                    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{ //強制將此屬性設到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('完成動畫');
                    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);
            }
        }

實現效果:透明度由1 變為0.3 ,z-index由10 變為20。

  到這裡一個較為完善的動畫函式就封裝完成了。

  如有任何疑問請留言。

  接下將介紹幾種通過js動畫效果實現各式輪播圖的案例......