第八周第三天笔记之运动库封装
2018-09-09 本文已影响0人
果木山
运动库封装
- 实质:一个元素从当前位置(ele决定)开始,在规定的时间(duration)内,以一种运动效果(effect),到达目标位置(target),然后做一件事情(callback)。是一个运动过程。
- 思路:
- 自执行函数封装,建立运动形式库gbEffect,创建运动函数animate();
- animate传入一个参数opt,为一个对象,实参对象中包含多个属性名,如:ele,duration,target对象,effect,callback等属性;
- animate函数创建流程:
- 1 对传入的实参值进行判断;
- 2 新建一个对象,里面添加默认样式
- 3 将传入的实参opt,所有属性赋值给defaultOpt,如果存在重新赋值,如果不存在,使用默认值;
- 4 获取defaultOpt里面的参数
- 5 获取运动形式,计算参数
- 5.1 获取运动形式:判断effect的数据类型,满足下面两种情况,就执行各自的代码,如果不满足,就使用默认值;
- 5.2 计算传入运动形式中的参数
- 6 添加定时器
- 6.1 变量累加
- 6.2 边界值判断
- 6.2.1 设置边界值
- 6.2.2 停止定时器
- 6.2.3 执行回调函数,进行下一步操作
- 6.2.4 阻断程序执行
- 6.3 获取最新位置及设置最新位置
- 6.3.1 运动方式获取最新位置;
- 6.3.2 分别设置最新位置
- 将自执行函数中的animate函数设置为window的全局变量;
- 知识点:
- 判断是否传入实参,并判断实参中是否传入元素,如以下代码:
function animate(opt) { //判断是否传入实参 opt=opt || {}; //ele和target为必须传的参数,所以只要有一个不存在就停止代码执行; if(!opt.ele || !opt.target) return;//如果传参错误,代码阻断不执行; }
- 新建一个新的defaultOpt对象,里面设置默认的属性,再将传入的对象的每个属性赋值给新的对象,如果属性已存在,则重新赋值,如果不存在则设置;defaultOpt的作用是设置默认的属性,如果传入的实参里面设置了defaultOpt里面的属性,就重新赋值,如果没有设置,就用默认值;
//1 新建一个对象,里面添加默认样式 var defaultOpt={ duration: 2000, effect: "linear" }; //2 将传入的实参opt,所有属性赋值给defaultOpt,如果存在重新赋值,如果不存在,使用默认值; for(var attr in opt){ defaultOpt[attr]=opt[attr]; } //总结:defaultOpt的作用是设置默认的属性,如果传入的实参里面设置了defaultOpt里面的属性,就重新赋值,如果没有设置,就用默认值; //下面所有代码不再使用opt,而使用defaultOpt;
- 回调函数调用及改变this指向的设置,如:
callback && callback.call(ele)
;利用"&&"来作判断,当callback存在的情况下,才会执行后面代码,后面代码中利用call来改变了回调函数中的this指向,使其指向ele元素,默认情况下,this指向window; - 透明度的设置问题,在target中设置透明度后,在运动形式中计算完输出的是字符串,不能设置成功,所以需要处理一下,利用Number进行转化;
//处理opacity的问题,属性值获取的都是字符串,不能设置成功 if(typeof linear ==="string"){ //linear=parseFloat(linear).toFixed(2);//此时转换后还是字符串 linear=Number(linear.slice(0,4));//此时转化后为数字,必须先截取在转化,直接用Number转化会变成NaN; }
- 代码
- 运动库代码:
(function () { //运动形式库 function animate(opt) { //0 对传入的实参值进行判断; opt=opt || {}; //ele和target为必须传的参数,所以只要有一个不存在就停止代码执行; if(!opt.ele || !opt.target) return;//如果传参错误,代码阻断不执行; //1 新建一个对象,里面添加默认样式 var defaultOpt={ duration: 2000, effect: "Linear" }; //2 将传入的实参opt,所有属性赋值给defaultOpt,如果存在重新赋值,如果不存在,使用默认值; for(var attr in opt){ defaultOpt[attr]=opt[attr]; } //总结:defaultOpt的作用是设置默认的属性,如果传入的实参里面设置了defaultOpt里面的属性,就重新赋值,如果没有设置,就用默认值; //下面所有代码不再使用opt,而使用defaultOpt; //3 获取defaultOpt里面的参数 var ele=defaultOpt.ele; var target=defaultOpt.target; var duration=defaultOpt.duration; var callback=defaultOpt.callback; var effect=defaultOpt.effect; var tempEffect=null; //4 获取运动形式,计算参数 //4.1 获取运动形式:判断effect的数据类型,满足下面两种情况,就执行各自的代码,如果不满足,就使用默认值; var ary=["Linear","EaseIn","EaseOut","EaseBoth","EaseInStrong","EaseOutStrong","EaseBothStrong","Elastic-In","Elastic-Out","Elastic-Both","Back-In","Back-Out","Back-Both","Bounce-In","Bounce-Out","Bounce-Both"]; if(typeof effect==="number"){ ary=ary[effect%ary.length].split("-"); tempEffect=ary.length>=2?gbEffect[ary[0]][ary[1]]:gbEffect[ary[0]]; }else if(typeof effect==="object"){ tempEffect=effect.length>=2?gbEffect[effect[0]][effect[1]]:gbEffect[effect[0]]; }else if(typeof effect==="string"){ tempEffect=gbEffect[effect];//此时tempEffect设置一个函数定义地址,不是函数名; } //4.2 计算传入运动形式中的参数 var begin={},change={}; for(var attr in target){ begin[attr]=utils.css(ele,attr); change[attr]=target[attr]-begin[attr]; } var time=0; //5 添加定时器 var timer=setInterval(function () { //5.1 变量累加 time+=30; //5.2 边界值判断 if(time>=duration){ //5.2.1 设置边界值 utils.css(ele,target); //5.2.2 停止定时器 clearInterval(timer); //5.2.3 执行回调函数,进行下一步操作 callback && callback.call(ele);//当callback存在的时候,执行回调函数,改变其中的this指向为元素; //5.2.4 阻断程序执行 return; } //5.3 获取最新位置及设置最新位置 for(var attr in change){ //5.3.1 运动方式获取最新位置; var cur=tempEffect(time,begin[attr],change[attr],duration); //处理opacity的问题,属性值获取的都是字符串,不能设置成功 if(typeof cur ==="string"){ //cur=parseFloat(cur).toFixed(2);//此时转换后还是字符串 cur=Number(cur.slice(0,4));//此时转化后为数字 } //5.3.2 分别设置最新位置 utils.css(ele,attr,cur); } },30) } window.animate=animate;//将私有函数设置为全局变量; })();
- 运动方式库:
var gbEffect= { Linear: function (t, b, c, d){ //匀速 return c*t/d + b; }, 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; }, EaseBoth: function(t, b, c, d){ //加速减速曲线 if ((t/=d/2) < 1) { return c/2*t*t + b; } return -c/2 * ((--t)*(t-2) - 1) + b; }, EaseInStrong: function(t, b, c, d){ //加加速曲线 return c*(t/=d)*t*t*t + b; }, EaseOutStrong: function(t, b, c, d){ //减减速曲线 return -c * ((t=t/d-1)*t*t*t - 1) + b; }, EaseBothStrong: 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; }, Elastic:{ In: function(t, b, c, d, a, p){ //正弦衰减曲线(弹动渐入) if (t === 0) { return b; } if ( (t /= d) == 1 ) { return b+c; } if (!p) { p=d*0.3; } if (!a || a < Math.abs(c)) { a = c; var s = p/4; } else { var 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; }, Out: function(t, b, c, d, a, p){ //正弦增强曲线(弹动渐出) if (t === 0) { return b; } if ( (t /= d) == 1 ) { return b+c; } if (!p) { p=d*0.3; } if (!a || a < Math.abs(c)) { a = c; var s = p / 4; } else { var 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; }, Both: function(t, b, c, d, a, p){ if (t === 0) { return b; } if ( (t /= d/2) == 2 ) { return b+c; } if (!p) { p = d*(0.3*1.5); } if ( !a || a < Math.abs(c) ) { a = c; var s = p/4; } else { var 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:{ In: function(t, b, c, d, s){ //回退加速(回退渐入) if (typeof s == 'undefined') { s = 1.70158; } return c*(t/=d)*t*((s+1)*t - s) + b; }, Out: function(t, b, c, d, s){ if (typeof s == 'undefined') { s = 3.70158; //回缩的距离 } return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; }, Both: 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:{ In: function(t, b, c, d){ //弹球减振(弹球渐出) return c - gbEffect.Bounce.Out(d-t, 0, c, d) + b; }, Out: 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; } return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b; }, Both: function(t, b, c, d){ if (t < d/2) { return gbEffect.Bounce.In(t*2, 0, c, d) * 0.5 + b; } return gbEffect.Bounce.Out(t*2-d, 0, c, d) * 0.5 + c*0.5 + b; } } }; //下列数组元素为所有的函数名; var gbEffectAry=["Linear","EaseIn","EaseOut","EaseBoth","EaseInStrong","EaseOutStrong","EaseBothStrong","Elastic-In","Elastic-Out","Elastic-Both","Back-In","Back-Out","Back-Both","Bounce-In","Bounce-Out","Bounce-Both"];
- 执行代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>运动库封装终极版</title> <style> *{ margin: 0; padding: 0; } #div1{ width: 80px; height: 80px; background-color: red; line-height: 80px; text-align: center; position: absolute; top: 10px; left:200px; opacity: 0.1; filter: alpha(opacity=10); } #div2{ width: 1px; height: 500px; margin-top: 10px; background-color: blue; position: absolute; top: 10px; left: 1100px; } </style> </head> <body> <div id="div1">物体</div> <div id="div2"></div> <script src="utils.js"></script> <script src="moveEffect.js"></script> <script src="01运动库封装终极版.js"></script> <script> var oDiv1=document.getElementById("div1"); animate({ ele:oDiv1, target:{ left:1000, top:400, opacity: 0.8 }, effect:1, duration: 2000, callback:function () { //默认情况下回调函数执行时,this指向window; //在调用时,用call改变this指向为ele; this.style.backgroundColor="yellow"; } }) </script> </body> </html>