原生JavaScript运动功能系列:定时定点运动

Posted 他乡踏雪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原生JavaScript运动功能系列:定时定点运动相关的知识,希望对你有一定的参考价值。

这篇博客剖析一个问题,就是怎么实现将元素指定时间运动到目标位置?前面的博客都是在处理运动行为,没有对运动时间做任何限定,只是因为清晰的分析运动行为和实现原理,要想一个动画函数具备健全的功能,并且可以随意使用,通过参数设定动画执行时间是非常有必要的一个设计。

在前面任意一种运动函数内,实质上只有一个变量,这个变量就是运动距离(缓冲运动中添加了因数),当运动距离变大时,运动时间就会变长,动画停止条件是由坐标来决定的。当指定运动时间时,运动速度就会同时受到运动距离和运动时间的限制,动画停止条件也是由时间来控制。

定时定点运动示例代码:

 1 //css
 2 div{
 3     width:100px;
 4     height:100px;
 5     background:red;
 6     position: absolute;
 7     left: 0px;
 8     opacity: 1;
 9 }
10 #top{
11     top: 100px;
12 }
13 #bottom{
14     top: 300px;    
15 }
16 //html
17 <div id="top"></div>
18 <div id="bottom"></div>
19 //js
20 var oDivArray = document.getElementsByTagName(\'div\');
21 var timer = null;
22 var targetObj = {
23     width:400,
24     height:400,
25     opacity:50,
26     left:300,
27     top:200
28 }
29 oDivArray[0].onclick = function(){
30     startMove(this,targetObj,3000,function(){
31         startMove(oDivArray[1],targetObj,3000);
32     });
33 }
34 function getStyle(obj,attr){
35     if(window.getComputedStyle){
36         return window.getComputedStyle(obj,false)[attr];
37     }else{
38         return obj.currentStyle[attr];
39     }
40 }
41 //运动方法startMove的参数:
42 //obj:运动物体;
43 //json:目标位置,最终样式值(键值对的形式合成的目标位置对象)
44 //speed:运动时间(指定运动的时间)
45 //callback:回调函数
46 function startMove(obj,json,speed,callback){
47     //初始位置,移动距离,当前位置
48     var initialPlace = {};
49     //新的位置(每次运动的目标点)
50     var nowPlace;
51     //结束之前的定时器
52     clearInterval(obj.timer);
53     //获取当前时间戳
54     var createTime = function(){
55         return (+new Date);
56     }
57     //动画开始的时间戳
58     var startTime = createTime();
59     //初始位置对象
60     for(var attr in json){
61         if(attr == \'opacity\'){
62             initialPlace[attr] = Math.round(parseFloat(getStyle(obj,attr))*100);
63         }else{
64             initialPlace[attr] = parseInt(getStyle(obj,attr));
65         }
66     }
67     //定时器
68     obj.timer = setInterval(function(){
69         //每次变化的时间
70         //剩余时间 = Math.max(0,运动开始的时间 + 运动执行事件 - 当前时间) -- 当剩余时间为负数时,返回0
71         var remaining = Math.max(0, startTime + speed - createTime());
72         //剩余时间比 = 剩余时间 / 运动时间
73         var temp = remaining / speed || 0;
74         //当前时间比 = 1 - 剩余时间比 -- 即执行到某处时间节点
75         var percent = 1 - temp;
76         //循环运动到时间节点位置
77         for(var  attr in json){
78             nowPlace = (json[attr] - initialPlace[attr]) * percent + initialPlace[attr];
79             if(attr == \'opacity\'){
80                 obj.style.opacity = nowPlace / 100;
81             }else{
82                 obj.style[attr] = nowPlace + \'px\';
83             }
84         }
85         //当前时间与运动时间比为1:1时,说明到达运动终点了,结束定时器,并判断是否有回调函数
86         if(percent == 1){
87             clearInterval(obj.timer);
88             typeof callback == \'function\' ? callback() : \'\';
89         }
90     },30);
91 }

示例还是基于链式运动的示例进行修改过来了,但是运动函数已经发生了质的变化。因为代码我都有些注释,就不详细解析了。提一个相对比较重要的点,这篇博客相对于前面的博客(运动系列),这篇博客的动画行为主要是受限定的运动时间来控制的,单次运动距离由运动实际运动时间比总(参数设置的时间)运动时间,来决定一次运动距离。通过时间比的方式来控制运动速度,和决定什么时候停止动画。

然后还有一个参数easing没有实现,如果没有这个参数,运动行为就都是匀速执行了,请看下面的改进方式:

 1 //在js全局定义运动行为对象
 2 var easingObj = {
 3     linear: function( p ) {
 4         return p;
 5     },
 6     swing: function( p ) {
 7         return 0.5 - Math.cos( p*Math.PI ) / 2;
 8     },
 9     background:function(k) {
10         if (k < (1 / 2.75)) {
11             return 7.5625 * k * k; 
12         } else if (k < (2 / 2.75)) {
13             return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; 
14         } else if (k < (2.5 / 2.75)) {
15             return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; 
16         } else { 
17             return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; 
18         } 
19     }
20 }
21 //然后在startMove运动方法的形参上添加参数easing;参数位置:第四个参数(索引3)
22 //然后设置默认运动行为或接收设置的运动行为
23 //对象行为 -- 默认:swing(匀速)
24 if(!easing){
25     easing = easingObj.swing;
26 }else{
27     easing = easingObj[easing];
28 }
29 //将运动节点位置那行代码修改
30 //实质是将percend用行为函数包裹起来
31 nowPlace = (json[attr] - initialPlace[attr]) * easing(percent) + initialPlace[attr];

最后调用代码:

oDivArray[0].onclick = function(){
    startMove(this,targetObj,3000,"",function(){
        startMove(oDivArray[1],targetObj,3000,"background");
    });
}

这个方法就完全模仿了jQuery的动画函数animate(),后期我会将这个方法封装,并且会提供缓动函数(easings库)插件接口,缓动函数库手册地址:https://easings.net/zh-cn。运动行为库相对来说还是有些局限性的,所以接下来我会在前面的示例基础上手写弹力效果和撞击效果。一步一步来吧。

相关技术博客参考:

以上是关于原生JavaScript运动功能系列:定时定点运动的主要内容,如果未能解决你的问题,请参考以下文章

原生JavaScript运动功能系列:多物体多值运动

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

原生js设计的运动框架

关于javascript的运动教程

原生JS封装时间运动函数

day38—JavaScript的运动基础-匀速运动