- 原生JavaScript运动功能系列(一):运动功能剖析与匀速运动实现
- 原生JavaScript运动功能系列(二):缓冲运动
- 原生JavaScript运动功能系列(三):多物体多值运动
- 原生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。运动行为库相对来说还是有些局限性的,所以接下来我会在前面的示例基础上手写弹力效果和撞击效果。一步一步来吧。
原文地址:https://www.cnblogs.com/ZheOneAndOnly/p/10407696.html
时间: 2024-11-05 12:31:25