第八周第三天笔记之运动库封装

运动库封装

  • 实质:一个元素从当前位置(ele决定)开始,在规定的时间(duration)内,以一种运动效果(effect),到达目标位置(target),然后做一件事情(callback)。是一个运动过程。
  • 思路:
    1. 自执行函数封装,建立运动形式库gbEffect,创建运动函数animate();
    2. animate传入一个参数opt,为一个对象,实参对象中包含多个属性名,如:ele,duration,target对象,effect,callback等属性;
    3. 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 分别设置最新位置
    4. 将自执行函数中的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>
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容