首页 > 代码库 > javascript运动系列第一篇——运动函数

javascript运动系列第一篇——运动函数

×
目录
[1]简单运动 [2]定时器管理 [3]分享到效果[4]移入移出[5]运动函数[6]透明度[7]多值[8]多物体

前面的话

  除了拖拽以外,运动也是javascript动画的一个基本操作。通过CSS属性transition和animation可以实现运动。但是,要进行更精细地操作,javascript运动是必不可少的。本文将详细介绍javascript运动

 

简单运动

  让一个元素在页面中运动起来很简单,设置定时器,改变定位元素的left或top值即可

<button id="btn">开始运动</button><button id="reset">还原</button><div id="test" style="height: 100px;width: 100px;background-color: pink;position:absolute;left:0;"></div><script>var timer;reset.onclick = function(){history.go();}btn.onclick = function(){    timer = setInterval(function(){        if(test.offsetLeft < 500){            test.style.left = test.offsetLeft + 10 + px;        }else{            test.style.left = 500px;            clearInterval(timer);        }        },30);}</script>

<iframe style="width: 100%; height: 150px;" src="http://sandbox.runjs.cn/show/8u11ggbl" frameborder="0" width="320" height="240"></iframe>

定时器管理

  上面的代码中没有进行定时器管理。当元素在运动的过程中,多次按下按钮,但会开启多个定时器,从而使元素运动速度加快

  有两种定时器管理方式

【1】开启新定时器前,消除旧定时器

  [注意]即使没有定时器的情况下,消除定时器也不会报错,只是静默失败

<button id="btn">开始运动</button><button id="reset">还原</button><div id="test" style="height: 100px;width: 100px;background-color: pink;position:absolute;left:0;"></div><script>var timer;reset.onclick = function(){history.go();}btn.onclick = function(){    clearInterval(timer);    timer = setInterval(function(){        if(test.offsetLeft < 500){            test.style.left = test.offsetLeft + 10 + px;        }else{            test.style.left = 500px;            clearInterval(timer);        }        },30);}</script>

<iframe style="width: 100%; height: 150px;" src="http://sandbox.runjs.cn/show/ifqfw6tn" frameborder="0" width="320" height="240"></iframe>

【2】当定时器未停止时,不允许开启新定时器

  [注意]由于定时器开启时,其返回值是一个不为0的整数,所以可以通过判断其返回值,来确定是否使用return语句

<button id="btn">开始运动</button><button id="reset">还原</button><div id="test" style="height: 100px;width: 100px;background-color: pink;position:absolute;left:0;"></div><script>var timer;reset.onclick = function(){history.go();}btn.onclick = function(){    if(timer) return;    timer = setInterval(function(){        if(test.offsetLeft < 500){            test.style.left = test.offsetLeft + 10 + px;        }else{            test.style.left = 500px;            clearInterval(timer);        }        },30);}</script>

<iframe style="width: 100%; height: 150px;" src="http://sandbox.runjs.cn/show/93s3nuaj" frameborder="0" width="320" height="240"></iframe>

“分享”效果

  现在要做一个类似于“分享到”侧边栏的效果

<style>#test{    width: 100px;    height: 100px;    background-color: lightblue;    text-align:center;    position:absolute;    top: 0;    left: -100px;}    #test-in{    width: 30px;    height: 60px;    background-color: orange;    margin-left: 100px;    position:relative;    top: 20px;}</style><div id="test">    <div id="test-in">分享到</div></div>    <script>test.onmouseover = function(){test.style.left = 0px;}test.onmouseout = function(){test.style.left = -100px;}</script>

<iframe style="width: 100%; height: 130px;" src="http://sandbox.runjs.cn/show/cbbghnxy" frameborder="0" width="320" height="240"></iframe>

移入移出

  如果把鼠标移入和鼠标移出都增加运动效果,则需要使用运动函数

  但是,有一个很重要的问题需要注意的是,鼠标移入移出的顺序问题

  如果把移入移出事件都加在父元素的身上,则需要做如下处理

  由于鼠标从子元素移动到父元素上时,会触发子元素的移出事件,通过冒泡也会触发父元素移出事件。此时,有两种方法解决该问题。一种是在子元素移出事件中阻止冒泡,另一种是在父元素移出事件设置target判断条件。当target为父元素本身时才执行

  鼠标从父元素移动到子元素的过程中,会按照顺序触发父元素的移出事件、子元素的移入事件以及父元素的移入事件

  为了避免触发移入事件。此时,使用开关变量会移入事件的代码进行限制。移出事件代码完成之前不执行移入事件代码

<script>var testIn = document.getElementById(test-in);var timer1,timer2;var onOff = false;test.onmouseover = function(){    if(!onOff){            clearInterval(timer1);        timer1 = setInterval(function(){            if(!onOff){                if(test.offsetLeft < 0){                    test.style.left = test.offsetLeft + 10 + px;                }else{                    test.style.left = 0;                    clearInterval(timer1);                    timer1 = 0;                }                                }else{                clearInterval(timer1);            }        },30);    }}test.onmouseout = function(e){    e = e || event;    var target = e.target || e.srcElement;    if(target === test){        //当触发父元素移出事件时,开启开关        onOff = true;        clearInterval(timer2);        timer2 = setInterval(function(){            if(test.offsetLeft > -100){                test.style.left = test.offsetLeft - 10 + px;            }else{                test.style.left = -100px;                clearInterval(timer2);                timer2 = 0;                //当运动结束后,关闭开关                onOff = false;            }            },30);            }}</script>

<iframe style="width: 100%; height: 130px;" src="http://sandbox.runjs.cn/show/ao5nqdqs" frameborder="0" width="320" height="240"></iframe>

运动函数

  从上面的代码中,可以看出运动部分的重复代码较多,把运动封装为带参数的函数更合适

<style>#test{width: 100px;height: 100px;background-color:lightblue;text-align:center;position:absolute;top: 0;left: -100px;}    #test-in{width: 30px;height: 60px;background-color: orange;margin-left: 100px;position:relative;top: 20px;}</style><div id="test">    <div id="test-in">分享到</div></div>    <script>var testIn = document.getElementById(test-in);var timer;test.onmouseover = function(){move(test,0,10);}test.onmouseout = function(){move(test,-100,-10)}function move(obj,target,speed){    clearInterval(timer);    timer = setInterval(function(){        if((obj.offsetLeft - target)*speed < 0){            obj.style.left = obj.offsetLeft + speed + px;        }else{            obj.style.left = target + px;            clearInterval(timer);            timer = 0;        }                    },16);        }    </script>

<iframe style="width: 100%; height: 130px;" src="http://sandbox.runjs.cn/show/plsf2q0v" frameborder="0" width="320" height="240"></iframe>

  由于不仅仅是left值可以做运动,其他属性(如width)也可以。所以,属性attr也应该作为参数提取出来

  这时就无法使用offset类属性,而应该使用计算样式的兼容函数getCSS()

function getCSS(obj,style){    if(window.getComputedStyle){        return getComputedStyle(obj)[style];    }    return obj.currentStyle[style];}   function move(obj,attr,target,speed){    clearInterval(timer);    timer = setInterval(function(){        var cur = parseInt(getCSS(obj,attr));        if((cur - target)*speed < 0){            obj.style.left = cur + speed + ‘px‘;        }else{            obj.style.left = target + ‘px‘;            clearInterval(timer);            timer = 0;        }                    },30);        }

 

透明度

  透明度是一个比较特殊的样式,因为IE8-浏览器不支持opacity,只可能通过滤镜的方式写成filter:alpha(opacity=透明值)

  但是,由于IE浏览器获取计算样式时,可以获得自定义样式,所以虽然opacity属性在IE8-浏览器无法生效,但是可以获得它的值

  如果透明度做运动的话,则需要对运动函数进行重新封装

<style>#test{width: 100px;height: 100px;background-color:lightblue;text-align:center;position:absolute;top: 0;left: 0;}    #test-in{width: 30px;height: 60px;background-color: orange;margin-left: 100px;position:relative;top: 20px;}</style><div id="test">    <div id="test-in">分享到</div></div>    <script>var testIn = document.getElementById(test-in);var timer;test.onmouseover = function(){move(test,opacity,0.1,-0.05);}test.onmouseout = function(){move(test,opacity,1,0.05)}function getCSS(obj,style){    if(window.getComputedStyle){        return getComputedStyle(obj)[style];    }    return obj.currentStyle[style];}   function move(obj,attr,target,speed){    clearInterval(timer);    var cur;    timer = setInterval(function(){        if(attr == opacity){            cur = Math.round(getCSS(obj,attr)*100);            if((cur - target*100)*speed < 0){                obj.style.opacity = (cur + speed*100)/100;                obj.style.filter = alpha(opacity= + (cur + speed*100) + );            }else{                obj.style.opacity = target;                obj.filter = alpha(opacity= + target + );                clearInterval(timer);                timer = 0;            }        }else{            cur = parseInt(getCSS(obj,attr));            if((cur - target)*speed < 0){                obj.style[attr] = cur + speed + px;            }else{                obj.style[attr] = target + px;                clearInterval(timer);                timer = 0;            }            }                    },30);        }    </script>

<iframe style="width: 100%; height: 130px;" src="http://sandbox.runjs.cn/show/shthvwpt" frameborder="0" width="320" height="240"></iframe>

多值

  如果一个元素有多个值同时运动时,像下面这样直接调用move()函数是有问题的

move(test,‘opacity‘,0.1,-0.05);move(test,‘left‘,-100,-1);

  因为函数里面定时器的变量timer是一个公共变量,当一个运动停止时,会清除定时器。这时另一个运动即使没有完成,定时器已经停止了,就无法继续运动了

  所以,合适的做法是在参数对象obj下面设置一个自定义属性timers,timers为一个空对象,然后将定时器返回值储存在timers对象下的attr属性中,此时两个定时器不会相互干扰

<style>#test{width: 100px;height: 100px;background-color: lightblue;text-align:center;position:absolute;top: 0;left: -100px;opacity:1;}    #test-in{width: 30px;height: 60px;background-color: orange;margin-left: 100px;position:relative;top: 20px;}</style><div id="test">    <div id="test-in">分享到</div></div>    <script>test.onmouseover = function(){    move(test,opacity,0.1,-0.05);    move(test,left,0,10);}test.onmouseout = function(){    move(test,opacity,1,0.05);    move(test,left,-100,-10);}function getCSS(obj,style){    if(window.getComputedStyle){        return getComputedStyle(obj)[style];    }    return obj.currentStyle[style];}   function move(obj,attr,target,speed){    if(!obj.timers){        obj.timers = {};    }    clearInterval(obj.timers[attr]);    var cur;    obj.timers[attr] = setInterval(function(){        if(attr == opacity){            cur = Math.round(getCSS(obj,attr)*100);            if((cur - target*100)*speed < 0){                obj.style.opacity = (cur + speed*100)/100;                obj.style.filter = alpha(opacity= + (cur + speed*100) + );            }else{                obj.style.opacity = target;                obj.filter = alpha(opacity= + target + );                clearInterval(obj.timers[attr]);                obj.timers[attr] = 0;            }        }else{            cur = parseInt(getCSS(obj,attr));            if((cur - target)*speed < 0){                obj.style[attr] = cur + speed + px;            }else{                obj.style[attr] = target + px;                clearInterval(obj.timers[attr]);                obj.timers[attr] = 0;            }            }            },30);        }    </script>

<iframe style="width: 100%; height: 130px;" src="http://sandbox.runjs.cn/show/zygaj8my" frameborder="0" width="320" height="240"></iframe>

多物体

  如果在页面中有多个元素利用运动函数进行运动。由于定时器返回值在不同元素不同属性中都不会受影响。所以,上面的运动函数可以直接使用

<style>div{height: 100px;width: 100px;position: absolute;left: 0;}#test1{background-color: pink;top: 40px;}#test2{background-color: lightblue;top: 150px;}</style><div id="test1">元素一</div><div id="test2">元素二</div><button id="btn">开始运动</button><button id="reset">还原</button>    <script>reset.onclick = function(){history.go();}btn.onclick = function(){    move(test1,width,300,10);    move(test1,left,100,10);    move(test2,width,500,20);    move(test2,left,200,10);}function getCSS(obj,style){    if(window.getComputedStyle){        return getComputedStyle(obj)[style];    }    return obj.currentStyle[style];}   function move(obj,attr,target,speed){    if(!obj.timers){        obj.timers = {};    }    clearInterval(obj.timers[attr]);    var cur;    obj.timers[attr] = setInterval(function(){        if(attr == opacity){            cur = Math.round(getCSS(obj,attr)*100);            if((cur - target*100)*speed < 0){                obj.style.opacity = (cur + speed*100)/100;                obj.style.filter = alpha(opacity= + (cur + speed*100) + );            }else{                obj.style.opacity = target;                obj.filter = alpha(opacity= + target + );                clearInterval(obj.timers[attr]);                obj.timers[attr] = 0;            }        }else{            cur = parseInt(getCSS(obj,attr));            if((cur - target)*speed < 0){                obj.style[attr] = cur + speed + px;            }else{                obj.style[attr] = target + px;                clearInterval(obj.timers[attr]);                obj.timers[attr] = 0;            }            }            },30);        }    </script>

<iframe style="width: 100%; height: 300px;" src="http://sandbox.runjs.cn/show/uyunuyee" frameborder="0" width="320" height="240"></iframe>

<script type="text/javascript">// 0){ return; } if(select[i].getBoundingClientRect().top <= 0 && select[i+1]){ if(select[i+1].getBoundingClientRect().top > 0){ change(oCon.children[i+2]) } }else{ change(oCon.children[select.length+1]) } }}document.body.onmousewheel = wheel;document.body.addEventListener(‘DOMMouseScroll‘,wheel,false);var oCon = document.getElementById("content");var close = oCon.getElementsByTagName(‘span‘)[0];close.onclick = function(){ if(this.innerHTML == ‘显示目录‘){ this.innerHTML = ‘ב; this.style.background = ‘‘; oCon.style.border = ‘2px solid #ccc‘; oCon.style.width = ‘‘; oCon.style.height = ‘‘; oCon.style.overflow = ‘‘; oCon.style.lineHeight = ‘30px‘; }else{ this.innerHTML = ‘显示目录‘; this.style.background = ‘#3399ff‘; oCon.style.border = ‘none‘; oCon.style.width = ‘60px‘; oCon.style.height = ‘30px‘; oCon.style.overflow = ‘hidden‘; oCon.style.lineHeight = ‘‘; }}for(var i = 2; i < oCon.children.length; i++){ oCon.children[i].onmouseover = function(){ this.style.color = ‘#3399ff‘; } oCon.children[i].onmouseout = function(){ this.style.color = ‘inherit‘; if(this.mark){ this.style.color = ‘#3399ff‘; } } oCon.children[i].onclick = function(){ change(this); } }function change(_this){ for(var i = 2; i < oCon.children.length; i++){ oCon.children[i].mark = false; oCon.children[i].style.color = ‘inherit‘; oCon.children[i].style.textDecoration = ‘none‘; oCon.children[i].style.borderColor = ‘transparent‘; } _this.mark = true; _this.style.color = ‘#3399ff‘; _this.style.textDecoration = ‘underline‘; _this.style.borderColor = ‘#2175bc‘; }// ]]></script><script type="text/javascript" src="http://files.cnblogs.com/files/xiaohuochai/contextMenu.js"></script>

javascript运动系列第一篇——运动函数