14. 定时器
定时器
14.1 定时调用
当希望一段程序可以每隔一段时间执行一次时,可以使用定时调用函数setInterval(),该函数有多个参数 参数
- 要做的事(通常是回调函数),该函数会每隔一段时间被调用一次,如果不是函数就传入一个字符串,这个字符串中的东西代表要做的事如"alert(123)"(不推荐这样写,最好还是写函数)
- 每次调用间隔的时间,单位是毫秒ms
- 往后的参数参数是要传入到回调函数中的实参,没有就不填
该函数的返回值是一个Number类型的数据,这个数字用来作为定时器的唯一标识(相当于ID值),可以通过变量赋值来接收这个返回值
var timer=setInterval(function(){
console.log(123);
},1000);
//每1S打印一次123
通过clearInerval()函数可以关闭一个通过setInterval()函数开启定时器,
该函数中需要一个定时器的标识作为参数,这样将关闭对应标识对应的定时器
clearInterval()函数可以接收任意参数,如果参数是一个有效的定时器的标识,则停止对应的定时器,如果参数不是一个有效的标识,则什么也不发生,也可以直接传入定时器传入的数值ID值cleatInterval(1)代表关闭第一个开启的定时器(但是不推荐这样用),最好还是通过变量赋值的标识来关闭定时器
var timer=setInterval(function(){ console.log(123); },1000); clearInterval(timer);//因为一运行就直接关闭了.所以不能打印出来
var num=1; var timer=setInterval(function(){ console.log(123); if(num==11){ clearInterval(timer) } },1000); //当num=11的时候关闭定时器不会再打印了
14.2 延时调用
希望一段程序不立刻执行,而是隔一段时间以后再执行,可以通过延时调用函数setTimeout(),并且延时调用只执行一次
,该函数的参数和用法和setInterval()一样
var timer=setTimeout(function(){ console.log(123); },1000); //1S后打印一次123,并且只会打印一次
通过clearTimeout()函数可以关闭一个通过setTimeout()函数开启定时器,
该函数中需要一个定时器的标识作为参数,这样将关闭对应标识对应的定时器,关闭方法同clearInterval()
var timer=setTimeout(function(){ console.log(123); },1000); clearTimeout(timer);//直接关闭定时器
**注意:**所有定时器中函数的异步操作都是放在同步操作的最后进行执行
延时调用和定时调用的异同
定时调用会执行多次,而延时调用只会执行一次
延时调用和定时调用的语法是相同的,并且在时间上是可以相互代替的,在开发中可根据自己需要去选择
14.3 运动动画
在JS中可以通过定时器的效果来实现动画效果,动画效果实质上时一帧一帧的图片效果拼接而来,当每秒钟的动画帧数超过60帧时,人眼就分辨不出来图片和动画,以此来实现动画效果
关于动画的函数
- requestAnimationFrame()函数(该函数不支持低版本IE浏览器),该函数的内部可以接收一个回调函数,在每一帧的动画结束后该函数就是自动执行内部的回调函数,以此达到动画效果式的移动,该函数的返回值也是一个代表数值类型的ID值
**注:**可以说该方法也是递归调用函数,但是事实上该方法对调用函数的次数做了限制,每秒只会调用60 次,而且不会无限占据系统资源
//兼容代码
window.requestAnimationFrame =window.requestAnimationFrame ||
function(cb) {
return setTimeout(cb, 1000 / 60);
};
cancelAnimationFrame()函数(该函数不支持低版本IE浏览器),该方法内部需要一个ID值作为参数,可以提前停止requestAnimationFrame()继续调用内部回调函数
//兼容代码 window.cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
动画效果函数
普通匀速动画效果(不通过数值的加减)
/* 参数: 对象obj 要改变的属性对象json(该对象内部是要改变的属性和要到达目标的属性值,不带单位,透明度100代表CSS的1) time--毫秒(ms)为单位,默认是1000ms callback回调函数(可选) */ function animation(obj, json, time = 1000, callback = function() {}) { //兼容代码 window.requestAnimationFrame = window.requestAnimationFrame || function(cb) { return setTimeout(cb, 1000 / 60); }; var startValue = {}, //开始属性值 changeValue = {}, //改变属性值 startTime = new Date(); //起始时间 for (var key in json) { var value; if (key === "opacity") { value = Math.round(parseFloat(getStyle(obj, key)) * 100); } else { value = parseFloat(getStyle(obj, key)); } startValue[key] = isNaN(value) ? 0 : value;//如果原来没有写值原来的值默认是0 changeValue[key] = parseFloat(json[key]) - startValue[key]; //改变值 } run(); //执行动画的函数 function run() { var nowTime = new Date() - startTime; var timescale = nowTime / time; //现在所用时间在总时间的比例 if (timescale >= 1) { timescale = 1; } else { requestAnimationFrame(run); } for (key in changeValue) { var value = timescale * changeValue[key] + startValue[key]; //每个时刻的目标值 if (key === "opacity") { obj.style.filter = "alpha(opacity:" + value + ")"; obj.style.opacity = value / 100; } else { obj.style[key] = value + "px"; } } if (timescale === 1) { callback(); } } } //获取对象属性 function getStyle(obj, name) { if (window.getComputedStyle) { return getComputedStyle(obj, null)[name]; } else { return obj.currentStyle[name]; } } //例子 var div=document.getElementById("box");//width:100px height:100px backgournd:red animation(div,{width:200,height:200},2000,function(){ div.style.display="none"; });
通过Tween.js实现的变速动画效果
/* 参数: 对象obj 要改变的属性对象json,该属性装有两个对象,data对象和option对象,data对象装的是内部要改变的属性和要到达目标的属性值,不带单位,透明度100代表CSS的1),option对象装的是运动方式easing属性和运动状态speed属性 time--毫秒(ms)为单位,默认是1000ms callback回调函数 */ function animation(obj, json, time = 1000, callback = function() {}) { //兼容代码 window.requestAnimationFrame = window.requestAnimationFrame || function(cb) { return setTimeout(cb, 1000 / 60); }; //控制速度的Tween.js var Tween = { Linear: { easeIn: function(t, b, c, d) { return (c * t) / d + 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; } }, Elastic: { easeIn: function(t, b, c, d, a, p) { var s; if (t == 0) return b; if ((t /= d) == 1) return b + c; if (typeof p == "undefined") p = d * 0.3; if (!a || a < Math.abs(c)) { s = p / 4; a = c; } else { 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) { var s; if (t == 0) return b; if ((t /= d) == 1) return b + c; if (typeof p == "undefined") p = d * 0.3; if (!a || a < Math.abs(c)) { a = c; s = p / 4; } else { 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) { var s; if (t == 0) return b; if ((t /= d / 2) == 2) return b + c; if (typeof p == "undefined") p = d * (0.3 * 1.5); if (!a || a < Math.abs(c)) { a = c; s = p / 4; } else { s = (p / (2 * Math.PI)) * Math.asin(c / a); } if (t < 1) return ( -0.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) * 0.5 + c + b ); } }, Back: { easeIn: function(t, b, c, d, s) { if (typeof s == "undefined") s = 1.70158; return c * (t /= d) * t * ((s + 1) * t - s) + b; }, easeOut: function(t, b, c, d, s) { if (typeof 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 (typeof 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; } }, Bounce: { easeIn: function(t, b, c, d) { return c - Tween.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 + 0.75) + b; } else if (t < 2.5 / 2.75) { return c * (7.5625 * (t -= 2.25 / 2.75) * t + 0.9375) + b; } else { return c * (7.5625 * (t -= 2.625 / 2.75) * t + 0.984375) + b; } }, easeInOut: function(t, b, c, d) { if (t < d / 2) { return Tween.Bounce.easeIn(t * 2, 0, c, d) * 0.5 + b; } else { return Tween.Bounce.easeOut(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b; } } } }; var startValue = {}, //开始属性值 changeValue = {}, //改变属性值 startTime = new Date(); //起始时间 var option = json.option;//获取option对象的值 var dataValue = json.data;//获取data对象的值 for (var key in dataValue) { var value; if (key === "opacity") { value = Math.round(parseFloat(getStyle(obj, key)) * 100); } else { value = parseFloat(getStyle(obj, key)); } startValue[key] = isNaN(value) ? 0 : value; changeValue[key] = parseFloat(dataValue[key]) - startValue[key]; //改变值 } var speed = option && option.speed; //控制的是速度的形式,不是具体快慢 var easing = option && option.easing; var speedArray = ["easeIn", "easeOut", "easeInOut"];//装有运动状态的数组 if (typeof option === "object") {//判断option是否有值 if ("easing" in option) {//option有值时是否改写了easing属性 speed = speed || 0;//默认是第一种运动状态 //匀速是强制速度是第一种形式 if (easing.toLowerCase() === "linear") { speed = 0; easing = "Linear"; } } else { //写了option,但是是空对象 speed = 0; easing = "Linear"; } } else { //没有写option,默认情况 speed = 0; easing = "Linear"; } run(); //执行动画的函数 function run() { var nowTime = new Date() - startTime; //当前时间 for (key in changeValue) { ///下方是Tween函数的自动用法 var value = Tween[easing][speedArray[speed]]( nowTime, startValue[key], changeValue[key], time ); //判断是否到达指定时间 if (time - nowTime <= 0) { value = Math.min(value, dataValue[key]); value = Math.max(value, dataValue[key]); //上方代码是为了让目标值一直都是指定值,减小误差 } if (key === "opacity") { obj.style.filter = "alpha(opacity:" + value + ")"; obj.style.opacity = value / 100; } else { obj.style[key] = value + "px"; } } //到达目标值执行回调函数 if (time - nowTime <= 0) { callback(); } else { requestAnimationFrame(run); } } } //获取对象属性 function getStyle(obj, name) { if (window.getComputedStyle) { return getComputedStyle(obj, null)[name]; } else { return obj.currentStyle[name]; } } //例子 var div=document.getElementById("box");//width:100px height:100px backgournd:red animation(div,{data:{width:200,height:200},option:{easing:"Bounce",speed:1}},2000, function(){ div.style.display="none"; });