原生JavaScript运动功能系列(二):缓冲运动
- 匀速运动实现回顾
- 缓冲运动剖析
- 示例实现
- 方法提取
匀速运动实现回顾及缓冲运动剖析:
在这个系列的上一篇博客中原生JavaScript运动功能系列(一):运动功能剖析与匀速运动实现就运动的核心功能组成,还剖析了匀速运动的实现,提取匀速运动的封装方法。这里我们回顾一下在匀速运动中存在三个核心逻辑:1.当最后的间距小于单位移动距离时,直接将位置移动到终点,并结束定时器执行;2.每次启动运动算法函数时,结束以前启动的定时器,防止重复启动运动算法函数出现定时器叠加;3.运动速度要设置正负值,保证正反双向都可以实现匀速运动(这一点在前一篇博客中没有提到)。
缓冲运动的特点
- 运动速度逐渐递减
- 其他特点与匀速运动算法基本一致
我想大家都有折纸的经历,小时候缺乏玩具的我们,各种折纸游戏和玩饰都是快乐的记忆,但是这里我不是要跟大家讨论折纸游戏和玩具的,如果大家有兴趣可以组个群玩。这里我要跟大家将的是,假设有一张纸,我们每对折一次,都会让边长减半,也就意味着每一次对折边长缩短的长度相比上一次就也是减半,直到纸折不动这个过程,边长缩减速度逐渐递减。这里就可以得到一个公式:边长/2=折叠后的边长;
有了折纸这个思路,聪明的你是否有了解决缓冲运动速度的计算方法呢?这里先提供HTML和CSS样式:
//html <div></div> <span></span> <button id="bit">run</button> //css div{ position: absolute; /* left: 0px; */ left: 600px;/* 同样适用 */ top: 0px; width: 100px; height: 100px; background: red; } span{ position: absolute; left: 300px; top: 1px; width: 1px; height: 100px; background-color: #000; } button{ margin-top: 150px; height: 25px; width: 35px; }
- 公式:距离/sum = 单次运动距离
- 代码实现:iSpeed = (target - dom.offsetLeft )/sum;
timer = setInterval(function (){ iSpeed = (300-obj.offsetLeft)/7; //实现物体运动代码... }
缓冲运动示例实现:
实现缓冲运动需要注意的几个计算陷阱:1.单次运动值小数陷阱;2.js操作像素添加小数值,但实际在渲染中只取整数部分;3.虽然通过终点位置减去当前位置可以自然实现正负值来控制运动方向,但因为前面两个原因,所以正向运动时要向上取整,反之则向下取整。
- 向上取整:Math.ceil(...)
- 向下取整:Math.floor(...)
1 var oDiv=document.getElementsByTagName("div")[0]; 2 var oBut=document.getElementById("bit"); 3 var timer=null; 4 oBut.onclick=function(){ 5 startMove(oDiv); 6 } 7 function startMove(obj){ 8 clearInterval(timer); 9 var iSpeed; 10 timer = setInterval(function (){ 11 iSpeed = (300-obj.offsetLeft)/7; 12 //console.log(iSpeed+"..."+Math.ceil(iSpeed)); 13 iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); 14 if(obj.offsetLeft === 300){ 15 clearInterval(timer); 16 }else{ 17 obj.style.left=obj.offsetLeft+iSpeed+'px'; 18 } 19 },30); 20 }
缓冲运动方法提取:
参数:要运动的元素,运动到指定位置,计算运动速度的因素;
注意1:需要在调用方法的作用域上声明timer变量;
注意2:示例代码指定位置只有距离浏览器左侧的距离,如果是复杂的运动功能,可以将target封装成一个位置对象,还包括距离浏览器上边距、元素的大小,元素的透明度;
注意3:计算运动的因素不能取0或1;示例代码取7,测试效果最好适应范围在运动距离的40分之一到50分子一之间比较合适。
1 function startMove(dom,target,divisor){ 2 clearInterval(timer); 3 var iSpeed; 4 timer = setInterval(function (){ 5 iSpeed = (target-dom.offsetLeft)/divisor; 6 iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed); 7 if(dom.offsetLeft === target){ 8 clearInterval(timer); 9 }else{ 10 dom.style.left=dom.offsetLeft+iSpeed+'px'; 11 } 12 },30); 13 }
下一篇运动系列博客针对多物体多值联动效果剖析。