zoukankan      html  css  js  c++  java
  • move.js 源码 学习笔记

    源码笔记:

      1 /* move.js
      2  * @author:flfwzgl https://github.com/flfwzgl
      3  * @copyright: MIT license 
      4  * Sorrow.X --- 添加注释,注释纯属个人理解(源码有稍微改动,方便阅读)
      5  * */
      6 
      7 ! function() {
      8 
      9     var PI = Math.PI,
     10         sin = Math.sin,
     11         cos = Math.cos,
     12         pow = Math.pow,
     13         abs = Math.abs,
     14         sqrt = Math.sqrt;
     15 
     16     var request = window.requestAnimationFrame,
     17         stopRequest = window.cancelAnimationFrame;
     18     var _move, _stopMove;    // 都是函数, 不支持requestAnimationFrame的浏览器就使用定时器
     19 
     20     //初始化运动函数和停止函数  
     21     if (request) {
     22         _move = function(fn, timer) {    // fn: 匿名函数, timer: 不同的空对象
     23             var step = function() {
     24                 if (!fn()) {    // fn函数返回值为假值则调用requestAnimationFrame方法(true代表运动结束)
     25                     timer.id = request(step);
     26                 };
     27             };
     28             step();    // 函数调用
     29         };
     30     } else {
     31         _move = function(fn, timer) {
     32             timer.id = setInterval(fn, 16);    // 采用定时器, 时间间隔不能低于16
     33         };
     34     };
     35     if (stopRequest) {
     36         _stopMove = function(timer) {
     37             stopRequest(timer.id);    // 停止动画调用
     38         };
     39     } else {
     40         _stopMove = function(timer) {
     41             clearInterval(timer.id);    // 关闭定时器
     42         };
     43     };
     44 
     45     var Move = function() {};    // Move构造函数
     46 
     47     var curve = Move.prototype = {    // Move原型
     48         extend: function(obj) {
     49             for (var k in obj) {
     50                 if (k in curve) {
     51                     console.warn('扩张的方法名' + k + ': 已经存在, 换个方法名吧!' );
     52                     return;
     53                 };
     54                 curve[k] = (function(moveType) {    // 给Move原型添加 动画曲线 方法
     55                     return function() {
     56                         return _doMove.call(this, arguments, moveType);    // 每个动画曲线方法实际调用_doMove函数
     57                     };
     58                 })(obj[k]);
     59             };
     60         }
     61     };
     62 
     63     /*****  动画曲线  ******/
     64     curve.extend({
     65         //定义域和值域均为[0, 1], 传入自变量x返回对应值y
     66         //先加速后减速
     67         ease: function(x) {
     68             // return -0.5*cos(PI * (2 - x)) + 0.5;
     69             if (x <= 0.5) return 2 * x * x;
     70             else if (x > 0.5) return -2 * x * x + 4 * x - 1;
     71         },
     72 
     73         // 初速度为0 ,一直加速
     74         easeIn: function(x) {
     75             return x * x;
     76         },
     77 
     78         //先慢慢加速1/3, 然后突然大提速, 最后减速
     79         ease2: function(x) {
     80             return x < 1 / 3 ? x * x : -2 * x * x + 4 * x - 1;
     81         },
     82 
     83         //初速度较大, 一直减速, 缓冲动画
     84         easeOut: function(x) {
     85             return pow(x, 0.8);
     86         },
     87 
     88         //碰撞动画
     89         collision: function(x) {
     90             var a, b; //a, b代表碰撞点的横坐标
     91             for (var i = 1, m = 20; i < m; i++) {
     92                 a = 1 - (4 / 3) * pow(0.5, i - 1);
     93                 b = 1 - (4 / 3) * pow(0.5, i);
     94                 if (x >= a && x <= b) {
     95                     return pow(3 * (x - (a + b) / 2), 2) + 1 - pow(0.25, i - 1);
     96                 }
     97             }
     98         },
     99 
    100         //弹性动画
    101         elastic: function(x) {
    102             return -pow(1 / 12, x) * cos(PI * 2.5 * x * x) + 1;
    103         },
    104 
    105         //匀速动画
    106         linear: function(x) {
    107             return x;
    108         },
    109 
    110         //断断续续加速减速
    111         wave: function(x) {
    112             return (1 / 12) * sin(5 * PI * x) + x;
    113         },
    114 
    115         //先向反方向移动一小段距离, 然后正方向移动, 并超过终点一小段, 然后回到终点
    116         opposite: function(x) {
    117             return (sqrt(2) / 2) * sin((3 * PI / 2) * (x - 0.5)) + 0.5;
    118         },
    119 
    120         // 相反的三次贝塞尔
    121         reverseEase: function (x) {    
    122             return 1 - Math.sqrt(1 - x * x);
    123         }
    124     });
    125 
    126     /**
    127      * 开始动画函数
    128      * arg: 用户要传的([0, 1000], 500, function(v){ ... }, fnEnd)
    129      * moveType: 曲线动画函数
    130      */
    131     function _doMove(arg, moveType) {
    132         var r,    // r => 过渡范围, 例如[0, 1000]   (必须传, 且传数组)
    133             d,    // d => 过渡时间, ms,             (可不传, 默认500) 
    134             fn,    // fn => 每一帧的回调函数, 传入当前过渡值v   (必须传) 
    135             fnEnd;    // fnEnd => 动画结束时回调               (可不传)    
    136 
    137         // 严格限制传入参数, 且传入的参数可以没有顺序
    138         for (var i = 0; i < 4; i++) {
    139             if (typeof arg[i] === 'object' && !r) r = arg[i];
    140             else if (typeof arg[i] === 'number' && !d) d = arg[i];
    141             else if (typeof arg[i] === 'function' && !fn) fn = arg[i];
    142             else if (typeof arg[i] === 'function' && !fnEnd) fnEnd = arg[i];
    143         };
    144 
    145         if (!r instanceof Array || !fn) return;    // 如果r不是数组或者fn不是函数(真值)就return掉
    146 
    147         d = d || 500;    // 过渡时间默认500ms
    148 
    149         var from = +new Date, //起始时间
    150             x = 0,    
    151             y,
    152             a = r[0],    // 过渡范围的起点
    153             b = r[1];    // 过度范围的终点
    154 
    155         var timer = 't' + Math.random();    // 随机数
    156 
    157         var self = this;    // 存一下Move的实例
    158 
    159         //用于保存定时器ID的对象, requestAnimation递归调用必须传入对象(给实例添加timer属性值为{})
    160         this[timer] = {};
    161 
    162         // 优先使用requestAnimationFrame否则setInterval定时器
    163         _move(function() {
    164             x = (+new Date - from) / d;
    165 
    166             if (x >= 1) {    // 动画结束
    167                 fn(b);    // 调用外部动画的回调函数且把过度范围的终点值作为参数传过去
    168                 if (fnEnd) fnEnd();    // 如果有动画结束回调函数就执行回调函数
    169                 return true;    // 返回真值停止调用requestAnimationFrame方法
    170             } else {    // 动画进行中
    171                 y = moveType(x);    // 调用动画曲线中的函数返回运动数字
    172                 fn(a + (b - a) * y);    // 调用外部动画的回调函数传参为 a + (b - a) * y
    173             };
    174         }, self[timer]);
    175 
    176         return function() {
    177             _stopMove(self[timer]);    // 调用cancelAnimationFrame方法停止动画
    178             return a + (b - a) * y;    // 返回动画停止后的运动数字
    179         };
    180     };
    181 
    182     // 抛出去
    183     if (typeof module === 'object' && module.exports) {
    184         module.exports = new Move;
    185     } else {
    186         if (window.move) {
    187             try {
    188                 console.warn('move has been declared!');
    189             } catch (e) {};
    190         } else {
    191             window.move = new Move;    // 抛出去的是个Move实例
    192         }
    193     };
    194 }();

    使用姿势:

            var box = document.querySelector("#box");
    
            // 扩展运动函数
            move.extend({
                fast: function(x) {
                    return x * x * x;
                },
                reverseEase: function (x) {    // 相反的三次贝塞尔
                    return 1 - Math.sqrt(1 - x * x);
                }
            })
    
            // 使用姿势
            var stop = move.reverseEase([0, 500], 1000, function(v){
                console.log(v);
                box.style.left = v + 'px';
            }, function(){
                console.log('动画完成');
            });
    
            setTimeout(function() {
                var val = stop();  //停止动画
                console.log('停止:' + val);
            }, 500);

    个人喜好,我改成了自己喜欢的源码,添加了随机取动画名字:

      1 ; (function() {
      2 
      3     var PI = Math.PI,
      4         sin = Math.sin,
      5         cos = Math.cos,
      6         pow = Math.pow,
      7         abs = Math.abs,
      8         sqrt = Math.sqrt;
      9 
     10     var request = window.requestAnimationFrame,
     11         stopRequest = window.cancelAnimationFrame;
     12     var _move, _stopMove;    // 都是函数, 不支持requestAnimationFrame的浏览器就使用定时器
     13 
     14     //初始化运动函数和停止函数  
     15     if (request) {
     16         _move = function(fn, timer) {    // fn: 匿名函数, timer: 不同的空对象
     17             var step = function() {
     18                 if (!fn()) {    // fn函数返回值为假值则调用requestAnimationFrame方法(true代表运动结束)
     19                     timer.id = request(step);
     20                 };
     21             };
     22             step();    // 函数调用
     23         };
     24     } else {
     25         _move = function(fn, timer) {
     26             timer.id = setInterval(fn, 16);    // 采用定时器, 时间间隔不能低于16
     27         };
     28     };
     29     if (stopRequest) {
     30         _stopMove = function(timer) {
     31             stopRequest(timer.id);    // 停止动画调用
     32         };
     33     } else {
     34         _stopMove = function(timer) {
     35             clearInterval(timer.id);    // 关闭定时器
     36         };
     37     };
     38 
     39     var Move = function() {    // Move构造函数
     40         this.aCurve = [];    // 曲线动画函数名集合
     41         this.init();
     42     };    
     43 
     44 
     45     var curve = Move.prototype = {    // Move原型
     46         // 初始化动画曲线 
     47         init: function() {
     48             this.extends({
     49                 //定义域和值域均为[0, 1], 传入自变量x返回对应值y
     50                 //先加速后减速
     51                 ease: function(x) {
     52                     // return -0.5*cos(PI * (2 - x)) + 0.5;
     53                     if (x <= 0.5) return 2 * x * x;
     54                     else if (x > 0.5) return -2 * x * x + 4 * x - 1;
     55                 },
     56 
     57                 // 初速度为0 ,一直加速
     58                 easeIn: function(x) {
     59                     return x * x;
     60                 },
     61 
     62                 //先慢慢加速1/3, 然后突然大提速, 最后减速
     63                 ease2: function(x) {
     64                     return x < 1 / 3 ? x * x : -2 * x * x + 4 * x - 1;
     65                 },
     66 
     67                 //初速度较大, 一直减速, 缓冲动画
     68                 easeOut: function(x) {
     69                     return pow(x, 0.8);
     70                 },
     71 
     72                 //碰撞动画
     73                 collision: function(x) {
     74                     var a, b; //a, b代表碰撞点的横坐标
     75                     for (var i = 1, m = 20; i < m; i++) {
     76                         a = 1 - (4 / 3) * pow(0.5, i - 1);
     77                         b = 1 - (4 / 3) * pow(0.5, i);
     78                         if (x >= a && x <= b) {
     79                             return pow(3 * (x - (a + b) / 2), 2) + 1 - pow(0.25, i - 1);
     80                         }
     81                     }
     82                 },
     83 
     84                 //弹性动画
     85                 elastic: function(x) {
     86                     return -pow(1 / 12, x) * cos(PI * 2.5 * x * x) + 1;
     87                 },
     88 
     89                 //匀速动画
     90                 linear: function(x) {
     91                     return x;
     92                 },
     93 
     94                 //断断续续加速减速
     95                 wave: function(x) {
     96                     return (1 / 12) * sin(5 * PI * x) + x;
     97                 },
     98 
     99                 //先向反方向移动一小段距离, 然后正方向移动, 并超过终点一小段, 然后回到终点
    100                 opposite: function(x) {
    101                     return (sqrt(2) / 2) * sin((3 * PI / 2) * (x - 0.5)) + 0.5;
    102                 },
    103 
    104                 // 相反的三次贝塞尔
    105                 reverseEase: function (x) {    
    106                     return 1 - Math.sqrt(1 - x * x);
    107                 }
    108             });
    109         },
    110 
    111         // 随机选择一个动画方法名
    112         getRd: function () {
    113             var preItem = null;
    114 
    115             return function () {
    116                 var arr = this.aCurve;
    117                 var index = Math.floor(Math.random() * arr.length),
    118                     item = arr[index],
    119                     result;
    120 
    121                 if (preItem != item) {
    122                     preItem = item;
    123                     result = item;
    124                 } else {
    125                     result = this.getRd(arr);
    126                 };
    127 
    128                 return result;
    129             };
    130         }(),
    131 
    132         // 扩张曲线动画
    133         extends: function(obj) {
    134             for (var k in obj) {
    135                 if (k in curve) {
    136                     console.warn('扩张的方法名' + k + ': 已经存在, 换个方法名吧!' );
    137                     return;
    138                 };
    139                 this.aCurve.push(k);
    140                 curve[k] = (function(moveType) {    // 给Move原型添加 动画曲线 方法
    141                     return function() {
    142                         return _doMove.call(this, arguments, moveType);    // 每个动画曲线方法实际调用_doMove函数
    143                     };
    144                 })(obj[k]);
    145             };
    146         }
    147     };
    148 
    149 
    150     /**
    151      * 开始动画函数
    152      * arg: 用户要传的([0, 1000], 500, function(v){ ... }, fnEnd)
    153      * moveType: 曲线动画函数
    154      */
    155     function _doMove(arg, moveType) {
    156         var r,    // r => 过渡范围, 例如[0, 1000]   (必须传, 且传数组)
    157             d,    // d => 过渡时间, ms,             (可不传, 默认500) 
    158             fn,    // fn => 每一帧的回调函数, 传入当前过渡值v   (必须传) 
    159             fnEnd;    // fnEnd => 动画结束时回调               (可不传)    
    160 
    161         // 严格限制传入参数, 且传入的参数可以没有顺序
    162         for (var i = 0; i < 4; i++) {
    163             if (typeof arg[i] === 'object' && !r) r = arg[i];
    164             else if (typeof arg[i] === 'number' && !d) d = arg[i];
    165             else if (typeof arg[i] === 'function' && !fn) fn = arg[i];
    166             else if (typeof arg[i] === 'function' && !fnEnd) fnEnd = arg[i];
    167         };
    168 
    169         if (!r instanceof Array || !fn) return;    // 如果r不是数组或者fn不是函数(真值)就return掉
    170 
    171         d = d || 500;    // 过渡时间默认500ms
    172 
    173         var from = +new Date, //起始时间
    174             x = 0,    
    175             y,
    176             a = r[0],    // 过渡范围的起点
    177             b = r[1];    // 过度范围的终点
    178 
    179         var timer = 't' + Math.random();    // 随机数
    180 
    181         var self = this;    // 存一下Move的实例
    182 
    183         //用于保存定时器ID的对象, requestAnimation递归调用必须传入对象(给实例添加timer属性值为{})
    184         this[timer] = {};
    185 
    186         // 优先使用requestAnimationFrame否则setInterval定时器
    187         _move(function() {
    188             x = (+new Date - from) / d;
    189 
    190             if (x >= 1) {    // 动画结束
    191                 fn(b);    // 调用外部动画的回调函数且把过度范围的终点值作为参数传过去
    192                 if (fnEnd) fnEnd();    // 如果有动画结束回调函数就执行回调函数
    193                 return true;    // 返回真值停止调用requestAnimationFrame方法
    194             } else {    // 动画进行中
    195                 y = moveType(x);    // 调用动画曲线中的函数返回运动数字
    196                 fn(a + (b - a) * y);    // 调用外部动画的回调函数传参为 a + (b - a) * y
    197             };
    198         }, self[timer]);
    199 
    200         return function() {
    201             _stopMove(self[timer]);    // 调用cancelAnimationFrame方法停止动画
    202             return a + (b - a) * y;    // 返回动画停止后的运动数字
    203         };
    204     };
    205 
    206     // 抛出去
    207     if (typeof module === 'object' && module.exports) {
    208         module.exports = Move;
    209     } else {
    210         if (window.Move) {
    211             try {
    212                 console.warn('Move has been declared!');
    213             } catch (e) {};
    214         } else {
    215             window.Move = Move;    // Move构造函数抛出去
    216         }
    217     };
    218 })();

    使用姿势:

            var move = new Move();
            
            move.extends({    // 自己自定义扩展
                fast: function(x) {
                    return x * x * x;
                },
                reverseEase: function (x) {    // 相反的三次贝塞尔
                    return 1 - Math.sqrt(1 - x * x);
                }
            })
    
            document.querySelector('#btn').addEventListener('click', function() {
                // 使用姿势
                var rd = move.getRd();
                var stop = move[rd]([0, 500], 1000, function(v){
                    console.log(v);
                    box.style.left = v + 'px';
                }, function(){
                    console.log('动画完成');
                });
    
                setTimeout(function() {
                    var val = stop();  //停止动画
                    console.log('停止:' + val);
                }, 500);
            }, false);

    ps:

         很喜欢的一个数字运动小型库,便于扩张各种运动。配合dnt的transform.js,真的很不错。

         很多ios和安卓的前端动画都能轻松写出来。

         比jq提供的动画更加强大和灵活。

         我只是个搬运工,喜欢的库自然会贴出原作者地址。

         看原作者怎么说明的:https://github.com/flfwzgl/move

    开心的做一个无忧无虑的码农,争取每天进步一点。
  • 相关阅读:
    CSRF跨站请求伪造
    FineReport 导出汉字乱码
    Java 程序中中文没有乱码,存入数据库后中文乱码问题
    分析函数
    Redis的持久化与主从复制
    分布式Redis的使用
    redis的介绍和安装
    Solr后台管理及SolrJ的使用
    Solr总结
    bootstrap 点击回到顶部 超简单
  • 原文地址:https://www.cnblogs.com/sorrowx/p/6490410.html
Copyright © 2011-2022 走看看