准备知识 |
1.定时器 |
使用定时器分为两步:设置定时器、设置等待时间
window.setInterval([function],[interval]); //设置一个定时器,到达指定的时间,每隔这么长时间都重复执行[function]
window.setTimeOut([function],[interval]); //只执行一次
定时器返回的是一个数字,代表当前是第几个定时器
清除定时器:
window.clearTimeOut(1); //数字表示清除掉第几个
window.clearInterval(timer2);
2.获取屏幕的宽高(兼容所有浏览器) |
var curWidth = document.documentElement.clientWidth || document.body.clientWidth; //获取当前屏幕的宽度
var curHeight = document.documentElement.clientHeight || document.body.clientHeight; //获取当前屏幕的高度
1.在指定时间内实现单方向匀速运动 |
让蓝色方块向右匀速运动,2s后到达屏幕右侧,每10ms走一步,如图所示:
(1)通过计算步长来实现:
示意图:
<script type="text/javascript">
var oBox = document.getElementById("box");
//盒子走的距离:
var maxLeft = (document.documentElement.clientWidth || document.body.clientWidth) - oBox.offsetWidth;
//运动的时间为2s
var duration = 2000;
//步长=距离/时间*10
var step = (maxLeft / duration) * 10;
var timer = window.setInterval(function () {
var curLeft = utils.css(oBox, "left"); //获取
if (curLeft >= maxLeft) {
window.clearInterval(timer);
return; //不加会有滚动条
}
curLeft += step;
utils.css(oBox, "left", curLeft); //设置
}, 10);
</script>
(2)通过计算每次运动的距离来实现:
<script type="text/javascript">
var oBox = document.getElementById('box'); //获取id是box的div元素
var duration = 2000; //运动的总时间为2s
//走的总距离/应该走的距离
var target = (document.documentElement.clientWidth || document.body.clientWidth) - oBox.offsetWidth;
var begin = utils.css(oBox, 'left'); //获取起始位置
var change = target - begin; //剩下的距离
var interval = 10; //每10毫秒执行一次
var time = null;
var timer = window.setInterval(function () { //建立定时器
time += interval;
if (time >= duration) { //当累加时间大于2秒时停止定时器
window.clearInterval(timer);
oBox.style.left = target + 'px'; //最后差一点,加这段代码补上最后的距离
return;
}
oBox.style.left = begin + (time / duration) * change + 'px'; //现在运动的位置
}, interval);
</script>
2.在指定步长内实现单方向匀速运动 |
让蓝色方块向右匀速运动,步长为5,到达屏幕右侧
注意边界问题:
<script type="text/javascript">
var oBox = document.getElementById("box");
//盒子走的距离:
var maxLeft = (document.documentElement.clientWidth || document.body.clientWidth) - oBox.offsetWidth;
var step = 5;
var timer = window.setInterval(function () {
var curLeft = utils.css(oBox, "left");
if (curLeft+step >= maxLeft) { //在进行边界判断的时候加上步长来进行处理
utils.css(oBox,"left",maxLeft);
window.clearInterval(timer);
return; //直接结束
}
curLeft += step;
utils.css(oBox, "left", curLeft);
}, 10);
</script>
3.使用setTimeout以及递归的方法实现 |
使用setTimeout设置动画,每一次在执行动画之前首先把上一次设置的那个没用的定时器清除掉,节约内存空间
<script type="text/javascript">
var oBox = document.getElementById("box");
//盒子走的距离:
var maxLeft = (document.documentElement.clientWidth || document.body.clientWidth) - oBox.offsetWidth;
var step = 5;
var timer = null; //接收定时器的返回值,设置成全局变量
function move() {
window.setTimeout(timer);
var curLeft = utils.css(oBox, "left");
if (curLeft + step >= maxLeft) { //在进行边界判断的时候加上步长来进行处理
utils.css(oBox, "left", maxLeft);
return; //直接结束
}
curLeft += step;
utils.css(oBox, "left", curLeft);
timer = window.setTimeout(move, 10);
}
move();
</script>
4.反弹运动动画 |
写两个按钮,控制着方块向左和向右,如图:
<script type="text/javascript">
var oBox = document.getElementById("box");
var minLeft = 0;
var maxLeft = (document.documentElement.clientWidth || document.body.clientWidth) - oBox.offsetWidth;
var timer = null;
function move(target) { //target:运动的目标位置
window.clearTimeout(timer);
var curLeft = utils.css(oBox, "left");
if (curLeft < target) { //向右
if (curLeft + 5 >= target) {
utils.css(oBox, "left", target);
return;
}
curLeft += 5;
utils.css(oBox, "left", curLeft);
} else if (curLeft > target) { //向左
if (curLeft - 5 <= target) {
utils.css(oBox, "left", target);
return;
}
curLeft -= 5;
utils.css(oBox, "left", curLeft);
} else { //不需要动
return;
}
timer = window.setTimeout(function () {
move(target);
}, 10);
}
document.getElementById("btn_left").onclick = function () {
move(minLeft);
};
document.getElementById("btn_right").onclick = function () {
move(maxLeft);
};
</script>
但是这样写性能不好,因为每一次到达时间的时候,都要先执行一次匿名函数,形成一个私有作用域,在匿名函数中再执行move。但是move中需要用到的数据值在第一次执行的move方法中,需要把匿名函数形成的这个私有作用域作为跳板找到之前的,这样就导致了匿名函数形成的这个私有作用域不能销毁。
解决方法:可以在move()中嵌套一个_move()方法
<script type="text/javascript">
var oBox = document.getElementById("box");
var minLeft = 0;
var maxLeft = (document.documentElement.clientWidth || document.body.clientWidth) - oBox.offsetWidth;
var timer = null;
function move(target) { //target:运动的目标位置
_move();
function _move() {
window.clearTimeout(timer);
var curLeft = utils.css(oBox, "left");
if (curLeft < target) { //向右
if (curLeft + 5 >= target) {
utils.css(oBox, "left", target);
return;
}
curLeft += 5;
utils.css(oBox, "left", curLeft);
} else if (curLeft > target) { //向左
if (curLeft - 5 <= target) {
utils.css(oBox, "left", target);
return;
}
curLeft -= 5;
utils.css(oBox, "left", curLeft);
} else { //不需要动
return;
}
timer = window.setTimeout(_move, 10);
}
timer = window.setTimeout(function () {
move(target);
}, 10);
}
document.getElementById("btn_left").onclick = function () {
move(minLeft);
};
document.getElementById("btn_right").onclick = function () {
move(maxLeft);
};
</script>
5.多方向匀速运动 |
top和left同时改变
<script type="text/javascript">
function Linear(t, b, c, d) {
return c * t / d + b;
}
var oBox = document.getElementById("box");
var beginLeft = utils.css(oBox, "left"), beginTop = utils.css(oBox, "top");
var targetLeft = 1000, targetTop = 500;
var changeLeft = targetLeft - beginLeft, changeTop = targetTop - beginTop;
var duration = 1000, time = 0;
oBox.timer = window.setInterval(function () {
time += 10;
if (time >= duration) {
utils.css(oBox, {
left: targetLeft,
top: targetTop
});
window.clearInterval(oBox.timer);
return;
}
var curLeft = Linear(time, beginLeft, changeLeft, duration);
var curTop = Linear(time, beginTop, changeTop, duration);
utils.css(oBox, {
left: curLeft,
top: curTop
});
}, 10);
</script>
6.创建运动动画库 |
~function () {
var tweenEffect = {
//匀速
Linear: function (t, b, c, d) {
return c * t / d + b;
},
//指数衰减的反弹缓动
Bounce: {
easeIn: function (t, b, c, d) {
return c - tweenEffect.Bounce.easeOut(d - t, 0, c, d) + b;
},
easeOut: function (t, b, c, d) {
if ((t /= d) < (1 / 2.75)) {
return c * (7.5625 * t * t) + b;
} else if (t < (2 / 2.75)) {
return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
} else if (t < (2.5 / 2.75)) {
return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
} else {
return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
}
},
easeInOut: function (t, b, c, d) {
if (t < d / 2) {
return tweenEffect.Bounce.easeIn(t * 2, 0, c, d) * .5 + b;
}
return tweenEffect.Bounce.easeOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
}
},
//二次方的缓动
Quad: {
easeIn: function (t, b, c, d) {
return c * (t /= d) * t + b;
},
easeOut: function (t, b, c, d) {
return -c * (t /= d) * (t - 2) + b;
},
easeInOut: function (t, b, c, d) {
if ((t /= d / 2) < 1) {
return c / 2 * t * t + b;
}
return -c / 2 * ((--t) * (t - 2) - 1) + b;
}
},
//三次方的缓动
Cubic: {
easeIn: function (t, b, c, d) {
return c * (t /= d) * t * t + b;
},
easeOut: function (t, b, c, d) {
return c * ((t = t / d - 1) * t * t + 1) + b;
},
easeInOut: function (t, b, c, d) {
if ((t /= d / 2) < 1) {
return c / 2 * t * t * t + b;
}
return c / 2 * ((t -= 2) * t * t + 2) + b;
}
},
//四次方的缓动
Quart: {
easeIn: function (t, b, c, d) {
return c * (t /= d) * t * t * t + b;
},
easeOut: function (t, b, c, d) {
return -c * ((t = t / d - 1) * t * t * t - 1) + b;
},
easeInOut: function (t, b, c, d) {
if ((t /= d / 2) < 1) {
return c / 2 * t * t * t * t + b;
}
return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
}
},
//五次方的缓动
Quint: {
easeIn: function (t, b, c, d) {
return c * (t /= d) * t * t * t * t + b;
},
easeOut: function (t, b, c, d) {
return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
},
easeInOut: function (t, b, c, d) {
if ((t /= d / 2) < 1) {
return c / 2 * t * t * t * t * t + b;
}
return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
}
},
//正弦曲线的缓动
Sine: {
easeIn: function (t, b, c, d) {
return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
},
easeOut: function (t, b, c, d) {
return c * Math.sin(t / d * (Math.PI / 2)) + b;
},
easeInOut: function (t, b, c, d) {
return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
}
},
//指数曲线的缓动
Expo: {
easeIn: function (t, b, c, d) {
return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
},
easeOut: function (t, b, c, d) {
return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
},
easeInOut: function (t, b, c, d) {
if (t == 0) return b;
if (t == d) return b + c;
if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
}
},
//圆形曲线的缓动
Circ: {
easeIn: function (t, b, c, d) {
return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
},
easeOut: function (t, b, c, d) {
return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
},
easeInOut: function (t, b, c, d) {
if ((t /= d / 2) < 1) {
return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
}
return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
}
},
//超过范围的三次方缓动
Back: {
easeIn: function (t, b, c, d, s) {
if (s == undefined) s = 1.70158;
return c * (t /= d) * t * ((s + 1) * t - s) + b;
},
easeOut: function (t, b, c, d, s) {
if (s == undefined) s = 1.70158;
return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
},
easeInOut: function (t, b, c, d, s) {
if (s == undefined) s = 1.70158;
if ((t /= d / 2) < 1) {
return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
}
return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
}
},
//指数衰减的正弦曲线缓动
Elastic: {
easeIn: function (t, b, c, d, a, p) {
if (t == 0) return b;
if ((t /= d) == 1) return b + c;
if (!p) p = d * .3;
var s;
!a || a < Math.abs(c) ? (a = c, s = p / 4) : s = p / (2 * Math.PI) * Math.asin(c / a);
return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
},
easeOut: function (t, b, c, d, a, p) {
if (t == 0) return b;
if ((t /= d) == 1) return b + c;
if (!p) p = d * .3;
var s;
!a || a < Math.abs(c) ? (a = c, s = p / 4) : s = p / (2 * Math.PI) * Math.asin(c / a);
return (a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b);
},
easeInOut: function (t, b, c, d, a, p) {
if (t == 0) return b;
if ((t /= d / 2) == 2) return b + c;
if (!p) p = d * (.3 * 1.5);
var s;
!a || a < Math.abs(c) ? (a = c, s = p / 4) : s = p / (2 * Math.PI) * Math.asin(c / a);
if (t < 1) return -.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
}
}
};
function move(curEle, target, duration, effect, callback) { //让哪个元素运动
var tempEffect = tweenEffect.Linear;
if (typeof effect == 'number') {
switch (effect) {
case 0:
tempEffect = tweenEffect.Linear;
break;
case 1:
tempEffect = tweenEffect.Bounce.easeIn;
break;
case 2:
tempEffect = tweenEffect.Quart.easeInOut;
}
} else if (effect instanceof Array) {
tempEffect = effect.length >= 2 ? tweenEffect[effect[0]][effect[1]] : tweenEffect[effect[0]];
} else if (typeof effect == 'function') { //用来做回调函数
callback = effect;
}
//根据target获取每一个方向的起始值和总距离
//首先清除定时器
window.clearInterval(curEle.tweenTimer);
var begin = {};
var change = {};
var time = 0;
var interval = 10;
for (var key in target) {
if (target.hasOwnProperty(key)) {
begin[key] = utils.getCss(curEle, key);
change[key] = target[key] - begin[key];
}
}
curEle.tweenTimer = window.setInterval(function () {
time += interval;
if (time >= duration) { //到达目标
window.clearInterval(curEle.tweenTimer);
utils.setGroupCss(curEle, target);
typeof callback == 'function' && callback.call(curEle); //回调函数判断
return;
}
//没到达目标,分别获取每个方向,然后并且设置
for (var key in target) {
if (target.hasOwnProperty(key)) {
var curPosi = tempEffect(time, begin[key], change[key], duration);
utils.setCss(curEle, key, curPosi);
}
}
}, interval);
}
//可以用return返回出来个一个对象,或者直接赋值给window
window.tweenAnimate = move;
}();