动画优化问题
[ ] 优化一:按固定步长运动:边界问题:step不一定是整数,不能正好到达目标。
- 【解决】加步长判断边界
[ ] 优化二:
setTimeout递归不传参
- 【解决】每次执行前首先把清除上次的定时器
[ ] 优化三:
setTimeout递归传参
作用域累积问题优化**- 【解决】:里面创建一个函数_move()不传参,在里面让setTimeout调用小函数_move()
[ ] 优化四:当前元素,在同一时间只运行一个动画(绑定多个动画事件时)
- 【解决】共享的定时器放到当前元素的自定义属性上,例如:box.timer
单方向运动
- [x] 指定时间(setInterval)
- [ ] 等间隔,按步长运动
- 注意:运动元素必须设置position,并且制定left的初始值123456789101112131415161718var box = utils.getElementsByClass('box')[0];console.log(box)var maxLeft = utils.getsetAttr('clientWidth') - box.offsetWidth;console.log(box.offsetWidth)var duration = 1000;var interval = 10;var speed = maxLeft / duration * interval;var timer = window.setInterval(function() {var curLeft = utils.getCss(box,"left");if (curLeft>= maxLeft) {window.clearInterval(timer);utils.setCss(box, 'left', maxLeft);return;}curLeft += speed;utils.setCss(box, "left", curLeft);}, interval);
- 注意:运动元素必须设置position,并且制定left的初始值
- [ ] 等间隔,按步长运动
- [ ] **等间隔,按时间占比计算**
图39
12345678910111213141516
var box = utils.getElementsByClass('box')[0];var duration = 1000; //从起点运动到终点需要1000msvar target = utils.getsetAttr('clientWidth') - box.offsetWidth; //要运动的距离var time = 0; //花费的时间var begin = utils.getCss(box,"left");var total = target - begin;var timer = window.setInterval(function (){ time += 5; //每次执行一次定时时间就多花费5ms if(time >= duration){ window.clearInterval(timer); utils.setCss(box,"left",target); return; } var curLeft = begin + (time/duration)*total; utils.setCss(box,"left",curLeft);},10);
- [x] 不定时间
- 步长固定时,
总距离/步长=多少步
- 步长固定时,
|
|
- 优化一:边界问题:不一定是整数,少走一步多走一步都不能正好到达目标位置,多走了半步,发现超了,又退回去的闪动。
- 【解决】加步长判断边界:先判断加一步超了吗,超出则直接赋最大值,没超出则再赋加这一步的值 123456789101112131415161718if (curLeft < target) {curLeft += speed;if (curLeft >= maxLeft) {window.clearInterval(box.timer);utils.setCss(box, "left", maxLeft);return;}utils.setCss(box, "left", curLeft);}//或者if (curLeft+step >= maxLeft) {window.clearInterval(box.timer);utils.setCss(box, "left", maxLeft);return;}curLeft += speed;utils.setCss(box, "left", curLeft);
轮循动画(左右反弹动画)
[x] 递归思想(setTimeout)
- [ ]
递归函数不传参
(setTimeout递归实现左右反弹动画)- 优化二:每次执行前首先把清除上次的定时器
- timer必须全局,因为每次执行move形成的私有作用域都不同,window.clearTimeout(timer);timer是本次私有作用域下的timer,而不是要清除的上次的timer1234567891011121314var step=5;var timer = null;//全局function move() {window.clearTimeout(timer);//清除上次定时器var curLeft = utils.getCss(box, "left");if (curLeft +step >= maxLeft) {utils.setCss(box, "left", maxLeft);return;}curLeft += step;utils.setCss(box, "left", curLeft);timer = window.setTimeout(move, 10); // move不需传参时,不需要写匿名函数}move();
- [ ]
[ ]
递归函数传参
(setTimeout递归实现左右反弹动画)- 【问题】存在作用域累积问题导致很多不销毁的私有作用域(每次执行到达时间都需要先执行一次匿名函数(形成私有作用域),在匿名函数中再执行move,move中需要用到的数据值target在第一次执行move方法中,需要把匿名函数形成的私有作用域作为跳板,导致匿名函数形成的私有作用不能销毁)
图40123456789101112131415161718192021222324252627282930313233343536var box = utils.getElementsByClass('box')[0];var maxLeft = utils.getsetAttr('clientWidth') - box.offsetWidth;var minLeft = 0;var step = 5;var timer = null;function move(target) {window.clearTimeout(timer); //清除上一次点击按钮启动的定时器 ???并没有清除定时器var curLeft = utils.getCss(box, "left");if (curLeft < target) { //向右if (curLeft + step >= maxLeft) {utils.setCss(box, "left", maxLeft);return;}curLeft += step;utils.setCss(box, "left", curLeft);} else if (curLeft > target) { //向左if (curLeft - step <= minLeft) { //定时器停止的拦截条件utils.setCss(box, "left", minLeft);return;}curLeft -= step;utils.setCss(box, "left", curLeft);} else { //相等的时候就是原地不动return;}timer = window.setTimeout(function(){move(target);},10);}utils.setCss(box, "left", 500);// 两次点击move执行形成的私有作用域不同document.getElementById('left').onclick = function() {move(minLeft);//私有作用域A}document.getElementById('right').onclick = function() {move(maxLeft); //私有作用域A
优化三:作用域累积问题优化
【解决】:需要传参的时,里面创建一个函数_move()不传参需要参数的参数在外层的函数作用域中找
,在里面让setTimeout调用小函数_move(),这样就不需要匿名函数来调用传参的move(target),也就不会再形成作用域累积问题
优化四:同一元素在同一时间只运行一个动画(下一个动画开始时,首先把上一个动画的定时器清除掉):保证当前元素所拥有动画接收定时器返回值的那个变量需要共享,把这个值放到当前元素的自定义属性上
【解决】共享的定时器放到当前元素的自定义属性上,例如:box.timer
|
|