javascript封装animate的过程

2020-12-24 257 1 编辑:深正互联 来源:互联网

首先,我们需要先封装一个css方法,用以获取元素的样式。

//elem    元素    attr    元素的属性名

function css(elem,attr){

        return elem.currentStyle ? elem.currentStyle[attr]  :   window.getComputedStyle(elem)[attr];

然后,我们想要一个元素的width动起来,怎么做?给它一个定时器,每隔一段时间改变它的width值,到了想要的值时就清除定时器。如果还想改变别的样式值呢?那么就给这个定时器封装成函数方法,把里面要改变的变成变量,需要用的时候,调用它,传入想改变的样式名就行了。


此时就有了这样的方法:


//elem 元素  attr  属性名  value 属性的改变值

function animate(elem,attr,value){

        var timer = setInterval(function(){

                //设置变量start存储元素要改变的样式的初值

                var start = parseInt( css(elem,attr) ),

                       

                //设置变量speed样式改变的速度

                var speed = (value-start)/10;

                //当speed负值或者正值时需要给它取整,以免出现start永远不能等于value的情况

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

                start += speed;

                if(start == value){

                        clearInterval(timer);

                }else{

                         elem.style[attr] = start + 'px';

                   }

            },13)

}


但是,这样的方法不能实现opacity的改变

那么就有了这样的方法:


function animate(elem,attr,value){

        var timer = setInterval(function(){

                //设置变量end存储元素要改变的样式的最终值

                var start = 0, end = 0;

                if(attr ==  'opacity'){

                     //Math.round防止无限小数兼容ie

                    start = Math.round( parseFloat( css(elem,attr) )*100 );

                    end = value*100; 

                }else{

                        start = parseInt( css(elem,attr) );

                        end = value; 

                    }

                var speed = (end-start)/10;

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

                start += speed;

                if(start == end){

                        clearInterval(timer);

                }else{

                        if(attr == 'opacity'){

                                elem.style.opacity = start/100;

                                 //兼容IE 

                                elem.style.filter='alpha(opacity='+start+')';                          

                         }else{

                                elem.style[attr] = start + 'px';

                             }

                 }

            },13)

}


这样的方法,只是在元素本身被设置过属性情况下,那如果元素没有设置这个你想要改变的属性呢?

我们先来看下,当元素没有设置属性值的时候,CSS方法获取的是什么。

比如,获取一个left,css(div,'left'),有的浏览器会返回0px,但是有的浏览器会返回一个undefined或者auto或者其他他非数字的值;同样,关于opacity这个属性,其他浏览器会返回1,但是IE浏览器会返回一个undefined。

软件开发

一般HTML+CSS布局的时候,大家通常会这样写透明度:filter:alpha(opacity=100);opacity:1;

因为IE浏览器的透明度是filter:alpha(opacity=100);这样的写法就是为了兼容IE的。


知道了原理,那么,这个animate就可以这样写了:

function animate(elem,attr,value){

        var timer = setInterval(function(){

               var start = 0, end = 0;

                if(attr ==  'opacity'){

                    //兼容IE  当没有设置fliter时,默认100;

                    if(!css(elem,attr)){

                           start = 100;

                      }else{

                              start = Math.round( parseFloat( css(elem,attr) )*100 );

                        }

                   end = value*100; 

                }else{

                        //兼容ie 没有设置attr时,默认0(不加parseInt,IE会报错)

                        if(!parseInt(css(elem,attr))){

                            start = 0; 

                        }else{

                               start = parseInt( css(elem,attr) );

                           }

                        end = value; 

                    }

                var speed = (end-start)/10;

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

                start += speed;

                if(start == end){

                        clearInterval(timer);

                }else{

                        if(attr == 'opacity'){

                                elem.style.opacity = start/100;

                                 //兼容IE 

                                elem.style.filter='alpha(opacity='+start+')';                          

                         }else{

                                elem.style[attr] = start + 'px';

                             }

                 }

            },13)

}


好了,元素单个的属性运动方法已经完毕。

那想要多个属性同时运动呢?

我们可以把attr和对应的value用对象存起来,比如这样 {width:100,height:100,opacity:1}。然后遍历这个对象,依次改变对象里的属性对应的值,也就是改变了元素的属性值。对象遍历我们用for in 方法。

比如,


        var json = {width:100,height:100,opacity:1};

           for(var i in json){

                console.log(i)

            } 


你会发现得到的是width,height,opacity这些字符串。那么json[i]就代表了json对象里的属性值。

还有,前面的方法,在实际运用中会出现BUG。因为可能会出现,上一次运动还没完,用户又开始运动,即开了多个定时器的情况。这样就会出现问题。

通常做法是在开始运动前就清除定时器,这样就不会出现问题。

我们的前面的方法里直接在定时器前面写clearInterval(timer)是不行的,会出错 timer is not defined 。

那么我们可以这样,把元素看成一个对象,把timer设置成元素的一个属性 ,即elem.timer。

所以,


function animate(elem,json){

        clearInterval(elem.timer);

        elem.timer = setInterval(function(){

                //遍历json,依次改变每个属性的属性值

               for(var attr in json){

                       var start = 0, end = 0;

                        if(attr ==  'opacity'){

                          //兼容IE 当没有设置fliter时,默认100;

                            if( !css(elem,attr) ){

                                   start = 100;

                              }else{

                                   //Math.round防止出现无限小数

                                  start = Math.round( parseFloat( css(elem,attr) )*100 );

                              }

                              end = parseFloat(json[attr])*100; 

                        }else{

                                 //兼容ie 没有设置attr时,默认0(不加parseInt,IE会报错)

                              if(!parseInt(css(elem,attr))){

                                start = 0; 

                            }else{

                                   start = parseInt( css(elem,attr) );

                              }

                               end =  parseInt(json[attr]); 

                        }

                    var speed = (end-start)/10;

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

                    start += speed;

                    if(start == end){

                            clearInterval(elem.timer);

                     }else{

                                if(attr == 'opacity'){

                                elem.style.opacity = start/100;

                                 //兼容IE 

                                elem.style.filter='alpha(opacity='+start+')';                          

                        }else{

                                elem.style[attr] = start + 'px';

                             }           

                } 

        },13)

}    


这样貌似写完了,其实还没完,这样写会有BUG,会出现只实现了第一个属性的运动,而其他属性的运动没有到达你想要的最终值。因为方法里是这样判定的,当start == end的时候,判定运动终止,但是,现在不止有一个start和end,第一个属性的start==end完成了,但是后面的属性的start==end并没有完成。

所以,我们可以用布尔值来做判定条件。


 function animate(elem,json){

        clearInterval(elem.timer);

        elem.timer = setInterval(function(){

                //运动终止条件

                var flag = true;

                //遍历json,依次改变每个属性的属性值

               for(var attr in json){

                       var start = 0, end = 0;

                        if(attr ==  'opacity'){

                        //兼容IE 当没有设置fliter时,默认100;

                            if( !css(elem,attr) ){

                                   start = 100;

                              }else{

                                   //Math.round防止出现无限小数

                                  start = Math.round( parseFloat( css(elem,attr) )*100 );

                              }

                              end = parseFloat(json[attr])*100; 

                        }else{

                               //兼容ie 没有设置attr时,默认0(不加parseInt,IE会报错)

                              if(!parseInt(css(elem,attr))){

                                start = 0; 

                            }else{

                                   start = parseInt( css(elem,attr) );

                              }

                               end =  parseInt(json[attr]); 

                        }

                    var speed = (end-start)/10;

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

                    start += speed;

                    //当start != end时,flag = false;,运动继续

                    if(start != end){

                            flag = false;

                     }

                      if(attr == 'opacity'){

                           elem.style.opacity = start/100;

                           //兼容IE 

                            elem.style.filter='alpha(opacity='+start+')';                          

                        }else{

                                elem.style[attr] = start + 'px';

                             }           

                } 

                 //当所有的start == end时,flag = true;,运动停止

                if(flag){

                         clearInterval(elem.timer);

                 }

                 

        },13)

}   

 

如果想把animate做成链式运动方法,很简单,只要多加个参数fn,在最后判定运动完成时回调函数就行。改变运动的快慢也很简单,只要再加个参数time。


所以最终版:


function animate(elem,json,time,fn){

        clearInterval(elem.timer);

        elem.timer = setInterval(function(){

                //运动终止条件

                var flag = true;

                //遍历json,依次改变每个属性的属性值

               for(var attr in json){

                       var start = 0, end = 0;

                        if(attr ==  'opacity'){

                        //兼容IE 当没有设置fliter时,默认100;

                            if( !css(elem,attr) ){

                                   start = 100;

                              }else{

                                   //Math.round防止出现无限小数

                                  start = Math.round( parseFloat( css(elem,attr) )*100 );

                              }

                              end = parseFloat(json[attr])*100; 

                        }else{

                            //兼容ie 没有设置attr时,默认0

                              if( !parseInt(css(elem,attr)) ){

                                start = 0; 

                            }else{

                                   //parseInt防止json对象里属性值带px

                                   start = parseInt( css(elem,attr) );

                              }

                               end =  parseInt(json[attr]); 

                        }

                        //如果有time实参传入,就执行speed = (end-start)/ time ,否则speed = (end-start)/10;

                        var speed = (end-start)/( time || 10 );

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

                        start += speed;

                        //当start != end时,flag = false;,运动继续

                        if(start != end){

                            flag = false;

                         }

                          if(attr == 'opacity'){

                           elem.style.opacity = start/100;

                           //兼容IE 

                            elem.style.filter='alpha(opacity='+start+')';                          

                          }else{

                                elem.style[attr] = start + 'px';

                            }           

                } 

                 //当所有的start == end时,flag = true;,运动停止

                if(flag){

                         clearInterval(elem.timer);

                       //运动终止时,如果有函数实参传入就执行回调函数

                        fn & fn(); 

                 }

                 

        },13)

}    

本站文章均为深正网站建设摘自权威资料,书籍,或网络原创文章,如有版权纠纷或者违规问题,请即刻联系我们删除,我们欢迎您分享,引用和转载,但谢绝直接搬砖和抄袭!感谢...
关注深正互联
多一份免费策划方案,总有益处。

请直接添加技术总监微信联系咨询

2
5