单方向指定时间内的匀速运动
回忆匀速运动:
y = kx + b;
这里的各参数表示的含义:
k:其实是速度,总路程/总时间
x:表示经过的时间
b:表示一开始所在的位置
y:表示当经过的时间是x的时候,走过的路程
用函数表示
/** * @param {[type]} start [开始位置] * @param {[type]} alter [改变的距离] * @param {[type]} curTime [已运行的时间] * @param {[type]} dur [总时间] * @return {[type]} [返回当前时间的所在位置] */ function linear(start, alter, curTime, dur) { return start + alter / dur * curTime; }
现在想让一个盒子用500ms从left=10匀速运动到20.
这里有一个问题,就是如果500ms的时候,对应的距离大于20,那么则调整为等于20
先把准备工作做好
var start = 10, target = 20, dur = 500; var alter = target - start, curTime = 0; var y = 0; // interval 影响curTime值 var interval = 11;
然后用两种定时方式实现
setInterval:
var timer = window.setInterval(animate, interval); function animate () { curTime += interval; y = linear(start, alter, curTime, dur); console.log(y); if (y >= target) { y = target; box.style.left = y + "px"; window.clearInterval(timer); timer = null; return; } box.style.left = y + "px"; }
setTimeout:
var timer = window.setTimeout(animate, interval); function animate () { window.clearTimeout(timer); curTime += interval; y = linear(start, alter, curTime, dur); console.log(y); if (y >= target) { y = target; box.style.left = y + "px"; timer = null; return; } box.style.left = y + "px"; timer = window.setTimeout(animate, interval); }
但是因为setInterval有累积效应,所以为了更好的效果,一般用setTimeout ,如上述代码看到的,学会将setInterval转化为setTimeout
(回调函数第一行加清除,最后一行加启动)
以下只写setTimeout
html结构 和 css样式
<style> #box { width: 100px; height: 100px; background-color: #f79; position: absolute; left: 10px; } </style> <div id="box"></div>
贴下全部代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> #box { width: 100px; height: 100px; background-color: #f79; position: absolute; left: 10px; } </style> </head> <body> <div id="box"></div> <script> /* * 匀速运动: * y = kx + b; * * 想想 这里的各参数表示的含义: * k:其实是速度,总路程/总时间 * x:表示经过的时间 * b:表示一开始所在的位置 * y:表示当经过的时间是x的时候,走过的路程 */ /** * [linear description] * @Author zhm * @DateTime 2017-02-21 * @param {[type]} start [开始位置] * @param {[type]} alter [改变的距离] * @param {[type]} curTime [已运行的时间] * @param {[type]} dur [总时间] * @return {[type]} [返回当前时间的所在位置] */ function linear(start, alter, curTime, dur) { return start + alter / dur * curTime; } /* * 现在想让盒子用500ms从left=10匀速运动到20. * 这里有一个问题,就是如果500ms的时候,对应的距离大于20,那么则调整为等于20 */ var start = 10, target = 20, dur = 500; var alter = target - start, curTime = 0; var y = 0; // interval 影响curTime值 var interval = 11; /* var timer = window.setInterval(animate, interval); function animate () { curTime += interval; y = linear(start, alter, curTime, dur); console.log(y); if (y >= target) { y = target; box.style.left = y + "px"; window.clearInterval(timer); timer = null; return; } box.style.left = y + "px"; } */ var timer = window.setTimeout(animate, interval); function animate () { window.clearTimeout(timer); curTime += interval; y = linear(start, alter, curTime, dur); console.log(y); if (y >= target) { y = target; box.style.left = y + "px"; timer = null; return; } box.style.left = y + "px"; timer = window.setTimeout(animate, interval); } </script> </body> </html>
索性将这一套变成定义成方法,这样单方向的匀速运动基本都能用了
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> #box { width: 100px; height: 100px; background-color: #f79; position: absolute; left: 10px; } </style> </head> <body> <div id="box"></div> <script> styleAnimate(box, "left", 100, 300, 10, linear); function linear(start, alter, curTime, dur) { return start + alter / dur * curTime; } function styleAnimate(ele, attr, target, dur, interval, way) { var start = rmPx(window.getComputedStyle(ele, null)[attr]) - 0, // 不要单位,且变成数字类型 alter = target - start, curTime = 0; var y = 0; var timer = window.setTimeout(animate, interval); function animate() { window.clearTimeout(timer); curTime += interval; way = way || linear; y = way(start, alter, curTime, dur); console.log(y); if (y >= target) { y = target; // 加单位,这里默认加px,如果是别的,加第二个参数即可 ele.style[attr] = addPx(y); timer = null; return; } ele.style[attr] = addPx(y); timer = window.setTimeout(animate, interval); } // 检测字符串有没有px之类的单位 function hasPx(str) { return /^(\d+)(px|em|rem)$/.test(str); } // 字符串有单位的话去掉 function rmPx(str) { if (hasPx(str)) { return /^(\d+)(px|em|rem)$/.exec(str)[1]; } return str; } // 给纯数字的且没单位的字符串加单位 function addPx(str, unit) { if (hasPx(str) || (str + "") === "0") { return str; } if (/^\d+$/.test(str)) { unit = unit || "px"; return str + unit; } } } </script> </body> </html>
以上情况只是 target>start,那么包含小于和等于的情况,对于最终的animate
function animate() { window.clearTimeout(timer); way = way || linear; y = way(start, alter, curTime, dur); // 这里开始判断target和start的大小 if (target = start) { return; } if (target > start) { curTime += interval; y >= target && afterTarget(); } else if (target > start) { curTime -= interval; y <= target && afterTarget(); } else { return; } console.log(y); // 超出范围之后,清除定时器,重置属性 function afterTarget() { y = target; // 加单位,这里默认加px,如果是别的,加第二个参数即可 ele.style[attr] = addPx(y); timer = null; return; } ele.style[attr] = addPx(y); timer = window.setTimeout(animate, interval); }