javascript运动系列第一篇——运动函数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript运动系列第一篇——运动函数相关的知识,希望对你有一定的参考价值。
前面的话
除了拖拽以外,运动也是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>
定时器管理
上面的代码中没有进行定时器管理。当元素在运动的过程中,多次按下按钮,但会开启多个定时器,从而使元素运动速度加快
有两种定时器管理方式
【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>
【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>
“分享”效果
现在要做一个类似于“分享到”侧边栏的效果
<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>
移入移出
如果把鼠标移入和鼠标移出都增加运动效果,则需要使用运动函数
但是,有一个很重要的问题需要注意的是,鼠标移入移出的顺序问题
如果把移入移出事件都加在父元素的身上,则需要做如下处理
由于鼠标从子元素移动到父元素上时,会触发子元素的移出事件,通过冒泡也会触发父元素移出事件。此时,有两种方法解决该问题。一种是在子元素移出事件中阻止冒泡,另一种是在父元素移出事件设置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>
运动函数
从上面的代码中,可以看出运动部分的重复代码较多,把运动封装为带参数的函数更合适
<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>
由于不仅仅是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>
多值
如果一个元素有多个值同时运动时,像下面这样直接调用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>
多物体
如果在页面中有多个元素利用运动函数进行运动。由于定时器返回值在不同元素不同属性中都不会受影响。所以,上面的运动函数可以直接使用
<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>
以上是关于javascript运动系列第一篇——运动函数的主要内容,如果未能解决你的问题,请参考以下文章