javascript运动详解
物体运动原理:通过改变物体的位置,而发生移动变化。
方法:
1.运动的物体使用绝对定位
2.通过改变定位物体的属性(left、right、top、bottom)值来使物体移动。例如向右或左移动可以使用offsetLeft(offsetRight)来控制左右移动。
步骤:
1、开始运动前,先清除已有定时器 (因为:是连续点击按钮,物体会运动越来越快,造成运动混乱)
2、开启定时器,计算速度
3、把运动和停止隔开(if/else),判断停止条件,执行运动
一.定时器
在javascritp中,有两个关于定时器的专用函数,它们是:
1.倒计定时器:timename=setTimeout("function();",delaytime);
2.循环定时器:timename=setInterval("function();",delaytime);
function()是定时器触发时要执行的是事件的函数,可以是一个函数,也可以是几个函数,或者javascript的语句也可以,单要用;隔开;delaytime则是间隔的时间,以毫秒为单位。
倒计时定时器就是在指定时间后触发事件,而循环定时器就是在间隔时间到来时反复触发事件,其区别在于:前者只是作用一次,而后者则不停地作用。
倒计时定时器一般用于页面上只需要触发一次的的情况,比如点击某按钮后页面在一定时间后跳转到相应的站点,也可以用于判断一个浏览者是不是你的站点上的“老客”,如果不是,你就可以在5秒或者10秒后跳转到相应的站点,然后告诉他以后再来可以在某个地方按某一个按钮就可以快速进入。
循环定时器一般用于站点上需要从复执行的效果,比如一个javascript的滚动条或者状态栏,也可以用于将页面的背景用飞雪的图片来表示。这些事件需要隔一段时间运行一次。
有时候我们也想去掉一些加上的定时器,此时可以用clearTimeout(timename) 来关闭倒计时定时器,而用clearInterval(timename)来关闭循环定时器。
二.运动研究
1.运动:匀速运动(让物体动起来)
对定时器的使用
给DIV加绝对定位
offsetLeft
问题:到达某个特定位罝停符
解决:做判断,符合条件时关掉定时器(存定时器timer)
速度变慢(一般不动时间,而是改数字-速度)
用变量存速度
问题:取7时,offsetLeft没有等于300的时候,div停不下来
解决:>=300 //停在 301
问题:到300后点击按钮还继续走
原因:点击按钮,执行函数,开定时器(执行当前函数一至少执行一次)
解决:加else (没有到达目标之前才执行)
问题:连续点击,速度变快
原因:每点击一次就开一个定时器,点击几次就有几个定时器同时工作
解决:保证每次只有一个定时器工作,先cearlnterval ()
示例1,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
<!DOCTYPE HTML> <html> <head> <meta charset= "utf-8" > <title>分享到</title> <style> #div1 {150px; height:200px; background:green; position:absolute; left:-150px;} #div1 span {position:absolute; 20px; height:60px; line-height:20px; background:blue; right:-20px; top:70px;} </style> <script> window.onload= function () { var oDiv=document.getElementById( 'div1' ); oDiv.onmouseover= function () { startMove(0); }; oDiv.onmouseout= function () { startMove(-150); }; }; var timer= null ; function startMove(iTarget) { var oDiv=document.getElementById( 'div1' ); clearInterval(timer); timer=setInterval( function (){ var speed=0; if (oDiv.offsetLeft>iTarget) { speed=-10; } else { speed=10; } if (oDiv.offsetLeft==iTarget) { clearInterval(timer); } else { oDiv.style.left=oDiv.offsetLeft+speed+ 'px' ; } }, 30); } </script> </head> <body> <div id= "div1" > <span>分享到</span> </div> </body> </html> |
效果如下:
示例2,淡入淡出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
<!DOCTYPE HTML> <html> <head> <meta charset= "utf-8" > <title>淡入淡出</title> <style> #div1 {200px; height:200px; background:red; filter:alpha(opacity:30); opacity:0.3;} </style> <script> window.onload= function () { var oDiv=document.getElementById( 'div1' ); oDiv.onmouseover= function () { startMove(100); }; oDiv.onmouseout= function () { startMove(30); }; }; var alpha=30; var timer= null ; function startMove(iTarget) { var oDiv=document.getElementById( 'div1' ); clearInterval(timer); timer=setInterval( function (){ var speed=0; if (alpha<iTarget) { speed=10; } else { speed=-10; } if (alpha==iTarget) { clearInterval(timer); } else { alpha+=speed; oDiv.style.filter= 'alpha(opacity:' +alpha+ ')' ; oDiv.style.opacity=alpha/100; } }, 30); } </script> </head> <body> <div id= "div1" ></div> </body> </html> |
效果如下:
匀速运动的停止条件
距离足够近
示例3,匀速运动的停止条件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
<!DOCTYPE HTML> <html> <head> <meta charset= "utf-8" > <title>匀速运动的停止条件</title> <style> #div1 {100px; height:100px; background:red; position:absolute; left:600px; top:50px;} #div2 {1px; height:300px; position:absolute; left:300px; top:0; background:black;} #div3 {1px; height:300px; position:absolute; left:100px; top:0; background:black;} </style> <script> var timer= null ; function startMove(iTarget) { var oDiv=document.getElementById( 'div1' ); clearInterval(timer); timer=setInterval( function (){ var speed=0; if (oDiv.offsetLeft<iTarget) { speed=7; } else { speed=-7; } if (Math.abs(iTarget-oDiv.offsetLeft)<=7) { clearInterval(timer); oDiv.style.left=iTarget+ 'px' ; } else { oDiv.style.left=oDiv.offsetLeft+speed+ 'px' ; } }, 30); } </script> </head> <body> <input type= "button" value= "到100" onclick= "startMove(100)" /> <input type= "button" value= "到300" onclick= "startMove(300)" /> <div id= "div1" ></div> <div id= "div2" ></div> <div id= "div3" ></div> </body> </html> |
2.变速运动(缓冲运动)
逐渐变慢,最后停止
距离越远速度越大
速度有距离决定
速度=(目标值-当前值)/缩放系数
如果没有缩放系数t速度太大,瞬间到达终点.没有过程
问题:并没有真正到达300
原因:速度只剩0.9 //像素是屏幕能够显示的最/J库位,并不会四舍五入掉
Math.ceil ()向上取整
Math.floor ()向下取整
问题:向左走,又差一块--Math.floor ()
判断:三目 speed=speed>0 ? Math.ceil ( speed ): Math.floor ( speed )
示例,缓冲运动:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<!DOCTYPE HTML> <html> <head> <meta charset= "utf-8" > <title>缓冲运动</title> <style> #div1 {100px; height:100px; background:red; position:absolute; left:600px; top:50px;} #div2 {1px; height:300px; position:absolute; left:300px; top:0; background:black;} </style> <script> function startMove() { var oDiv=document.getElementById( 'div1' ); setInterval( function (){ var speed=(300-oDiv.offsetLeft)/10; speed=speed>0?Math.ceil(speed):Math.floor(speed); oDiv.style.left=oDiv.offsetLeft+speed+ 'px' ; document.title=oDiv.offsetLeft+ ',' +speed; }, 30); } </script> </head> <body> <input type= "button" value= "开始运动" onclick= "startMove()" /> <div id= "div1" ></div> <div id= "div2" ></div> </body> </html> |
效果如下:
3.多物体运动
多个div ,鼠标移入变宽
运动框架传参obj,知道让哪个物体动起来
用到缓冲一定要取整
问题:div没运动回去 //清除前一个定时器
原因:只有一个定时器
解决:加物体上的定时器,使每个物体都有一个定时器。定时器作为物体属性
多个div淡入淡出
首先关闭物体上的定时器
经验:多物体运动框架所有东西都不能共用
问题:不是因为定时器,而是因为alpha
解决:作为属性附加到物体上 /不以变量形式存在
offset 的 bug
加border变宽
offsetWith并不是真正的width ,它获取的是盒模型尺寸
解决:躲着 宽度扔到行间,parselnt ( oDiv.style.width )
进一步解决: getStyle ( obj, name ) currentStyle , getComputedStyle
加border ,只要offset就有问题 去掉offset
示例,多物体运动:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
<!DOCTYPE HTML> <html> <head> <meta charset= "utf-8" > <title>无标题文档</title> <style> div {100px; height:50px; background:red; margin:10px; border:10px solid black;} </style> <script> window.onload= function () { var aDiv=document.getElementsByTagName( 'div' ); for ( var i=0;i<aDiv.length;i++) { aDiv[i].timer= null ; aDiv[i].onmouseover= function () { startMove( this , 400); }; aDiv[i].onmouseout= function () { startMove( this , 100); }; } }; function startMove(obj, iTarget) { clearInterval(obj.timer); obj.timer=setInterval( function (){ var speed=(iTarget-obj.offsetWidth)/6; speed=speed>0?Math.ceil(speed):Math.floor(speed); if (obj.offsetWidth==iTarget) { clearInterval(obj.timer); } else { obj.style.width=obj.offsetWidth+speed+ 'px' ; } }, 30); } </script> </head> <body> <div></div> <div></div> <div></div> </body> </html> |
效果如下:
4.任意值运动
任意值运动的单位分为透明度和px。
px单位的任意值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
<!DOCTYPE HTML> <html> <head> <meta charset= "utf-8" > <title>无标题文档</title> <style> div {200px; height:200px; margin:20px; float:left; background:yellow; border:10px solid black; font-size:14px;} </style> <script> window.onload= function () { var oDiv1=document.getElementById( 'div1' ); oDiv1.onmouseover= function (){startMove( this , 'height' , 400);}; oDiv1.onmouseout= function (){startMove( this , 'height' , 200);}; var oDiv2=document.getElementById( 'div2' ); oDiv2.onmouseover= function (){startMove( this , 'width' , 400);}; oDiv2.onmouseout= function (){startMove( this , 'width' , 200);}; var oDiv3=document.getElementById( 'div3' ); oDiv3.onmouseover= function (){startMove( this , 'fontSize' , 50);}; oDiv3.onmouseout= function (){startMove( this , 'fontSize' , 14);}; var oDiv4=document.getElementById( 'div4' ); oDiv4.onmouseover= function (){startMove( this , 'borderWidth' , 100);}; oDiv4.onmouseout= function (){startMove( this , 'borderWidth' , 10);}; }; function getStyle(obj, name) { if (obj.currentStyle){ return obj.currentStyle[name];} else { return getComputedStyle(obj, false )[name];} } function startMove(obj, attr, iTarget) { clearInterval(obj.timer); obj.timer=setInterval( function (){ var cur=parseInt(getStyle(obj, attr)); var speed=(iTarget-cur)/6; speed=speed>0?Math.ceil(speed):Math.floor(speed); if (cur==iTarget) { clearInterval(obj.timer); } else { obj.style[attr]=cur+speed+ 'px' ; } }, 30); } </script> </head> <body> <div id= "div1" >变高</div> <div id= "div2" >变宽</div> <div id= "div3" >safasfasd</div> <div id= "div4" ></div> </body> </html> |
效果如下:
透明度的任意值,需要做判断:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
判断 var cur=0 if ( attr== 'opacity ' ){ cur=parseFloat ( getStyle ( obj, attr)) *100 } else { } 设置样式判断 if ( attr== 'opacity ' ){ obj.style.fiIter = 'alpha ( opacity: ' ( cur+speed ) + ')' obj.style.opacity= ( cur+speed ) /100 } else { } |
5.链式运动
多出来的一个参数,只有传进去的时候才调用
鼠标移入变宽,结束之后弹出abc
先横向展开.再以向展开
鼠标移出,先变回不透明,变矮,变窄
三.封装运动框架(源码下载:https://github.com/jingwhale/jsmove/blob/master/move.js)
基于以上的分析与总结,封装运动框架move.js如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
function getStyle(obj, name) { if (obj.currentStyle) { return obj.currentStyle[name]; } else { return getComputedStyle(obj, false )[name]; } } function startMove(obj, json, fnEnd) { clearInterval(obj.timer); obj.timer=setInterval( function (){ var bStop= true ; //假设:所有值都已经到了 for ( var attr in json) { var cur=0; if (attr== 'opacity' ) { cur=Math.round(parseFloat(getStyle(obj, attr))*100); } else { cur=parseInt(getStyle(obj, attr)); } var speed=(json[attr]-cur)/6; speed=speed>0?Math.ceil(speed):Math.floor(speed); if (cur!=json[attr]) bStop= false ; if (attr== 'opacity' ) { obj.style.filter= 'alpha(opacity:' +(cur+speed)+ ')' ; obj.style.opacity=(cur+speed)/100; } else { obj.style[attr]=cur+speed+ 'px' ; } } if (bStop) { clearInterval(obj.timer); if (fnEnd)fnEnd(); } }, 30); } |
move.js运动框架基本满足现在网页上所有动画的需求(不包括css3)。
四.应用应用
1,完成如下效果:
js代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
<script src= "move.js" ></script> <script> window.onload= function () { var oDiv=document.getElementById( 'play' ); var aBtn=oDiv.getElementsByTagName( 'ol' )[0].getElementsByTagName( 'li' ); var oUl=oDiv.getElementsByTagName( 'ul' )[0]; var now=0; for ( var i=0;i<aBtn.length;i++) { aBtn[i].index=i; aBtn[i].onclick= function () { now= this .index; tab(); }; } function tab() { for ( var i=0;i<aBtn.length;i++) { aBtn[i].className= '' ; } aBtn[now].className= 'active' ; startMove(oUl, {top: -150*now}); } function next() { now++; if (now==aBtn.length){now=0;} tab(); } var timer=setInterval(next, 2000); oDiv.onmouseover= function (){clearInterval(timer);}; oDiv.onmouseout= function (){timer=setInterval(next, 2000);}; }; </script> |
应用2,完成如下效果:
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
<!DOCTYPE html> <html> <head> <meta http-equiv= "Content-Type" content= "text/html; charset=utf-8" /> <title>无标题文档</title> <style type= "text/css" > ..... </style> <script type= "text/javascript" src= "move.js" ></script> <script type= "text/javascript" > window.onload= function () { var oBtn=document.getElementById( 'but' ); var oBottom=document.getElementById( 'zns_bottom' ); var oBox=document.getElementById( 'zns_box' ); var oBtnClose=document.getElementById( 'btn_close' ); oBox.style.display= 'block' ; var initBottomRight=parseInt(getStyle(oBottom, 'right' )); var initBoxBottom=parseInt(getStyle(oBox, 'bottom' )); oBox.style.display= 'none' ; oBtn.onclick=openHandler; oBtnClose.onclick=closeHandler; function openHandler() { startMove(oBottom, {right: 0}, function (){ oBox.style.display= 'block' ; startMove(oBox, {bottom: 0}); }); oBtn.className= 'but_hide' ; oBtn.onclick=closeHandler; } function closeHandler() { startMove(oBox, {bottom: initBoxBottom}, function (){ oBox.style.display= 'none' ; startMove(oBottom, {right: initBottomRight}, function (){ oBtn.className= 'but_show' ; }); }); oBtn.onclick=openHandler; } }; </script> </head> <body> ...... </body> </html> |