zoukankan      html  css  js  c++  java
  • AlloyTouch.js 源码 学习笔记及原理说明

    alloyTouch这个库其实可以做很多事的, 比较抽象, 需要我们用户好好的思考作者提供的实例属性和一些回调方法(touchStart,
    change, touchMove, pressMove, tap, touchEnd, touchCancel, reboundEnd, animationEnd, correctionEnd).
    哇, 提供了这么多回调啊, 因为我也刚玩,用到的不多。
    change回调很常用(比如上拉,下拉刷新要用到),配合touchStart, animationEnd等,看需求吧
    touchEnd, animationEnd(写轮播用到)。
    因为我也刚用, 暂时没怎么研究其他回调的用法,但是我都在源码中标记了什麽时候触发回调的。

    原理说明:
    alloyTouch库其实是一个数字运动的库,我再看源码时,看见源码里_end()中计算各种比值和目标值,目的就是让dom在什么时间内运动到什么目标值。
    当然对外也提供了to方法,让dom运动到用户指定的目标值。具体看源码注释。

    源码笔记:

        由于demo没全看完,所以有的注释理解的不太到位。有问题,欢迎指正。

      1 /* AlloyTouch v0.2.1
      2  * By AlloyTeam http://www.alloyteam.com/
      3  * Github: https://github.com/AlloyTeam/AlloyTouch
      4  * MIT Licensed.
      5  * Sorrow.X --- 添加注释,注释纯属个人理解
      6  */
      7 
      8  // 兼容不支持requestAnimationFrame的浏览器
      9 ;(function () {
     10     'use strict';
     11 
     12     if (!Date.now)
     13         Date.now = function () { return new Date().getTime(); };
     14 
     15     var vendors = ['webkit', 'moz'];
     16     for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
     17         var vp = vendors[i];
     18         window.requestAnimationFrame = window[vp + 'RequestAnimationFrame'];
     19         window.cancelAnimationFrame = (window[vp + 'CancelAnimationFrame']
     20                                    || window[vp + 'CancelRequestAnimationFrame']);
     21     }
     22     if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy
     23         || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
     24         var lastTime = 0;
     25         window.requestAnimationFrame = function (callback) {
     26             var now = Date.now();
     27             var nextTime = Math.max(lastTime + 16, now);
     28             return setTimeout(function () { callback(lastTime = nextTime); },
     29                               nextTime - now);
     30         };
     31         window.cancelAnimationFrame = clearTimeout;
     32     }
     33 }());
     34 
     35 (function () {
     36 
     37     // 给元素绑定事件, 默认冒泡
     38     function bind(element, type, callback) {
     39         element.addEventListener(type, callback, false);
     40     };
     41 
     42     // 三次贝塞尔
     43     function ease(x) {
     44         return Math.sqrt(1 - Math.pow(x - 1, 2));
     45     };
     46 
     47     // 相反的三次贝塞尔
     48     function reverseEase(y) {
     49         return 1 - Math.sqrt(1 - y * y);
     50     };
     51 
     52     // INPUT|TEXTAREA|BUTTON|SELECT这几个标签就不用阻止默认事件了
     53     function preventDefaultTest(el, exceptions) {
     54         for (var i in exceptions) {
     55             if (exceptions[i].test(el[i])) {
     56                 return true;
     57             };
     58         };
     59         return false;
     60     };
     61 
     62     var AlloyTouch = function (option) {
     63         
     64         this.element = typeof option.touch === "string" ? document.querySelector(option.touch) : option.touch;    // 反馈触摸的dom
     65         this.target = this._getValue(option.target, this.element);    // 运动的对象
     66         this.vertical = this._getValue(option.vertical, true);    // 不必需,默认是true代表监听竖直方向touch
     67         this.property = option.property;    // 被滚动的属性
     68         this.tickID = 0;
     69 
     70         this.initialValue = this._getValue(option.initialValue, this.target[this.property]);    // 被运动的属性的初始值,默认从Transform原始属性拿值
     71         this.target[this.property] = this.initialValue;    // 给运动的属性赋值
     72         this.fixed = this._getValue(option.fixed, false);
     73         this.sensitivity = this._getValue(option.sensitivity, 1);    // 默认是1, 灵敏度
     74         this.moveFactor = this._getValue(option.moveFactor, 1);    // move时的运动系数
     75         this.factor = this._getValue(option.factor, 1);    // 系数
     76         this.outFactor = this._getValue(option.outFactor, 0.3);    // 外部系数
     77         this.min = option.min;    // 不必需,滚动属性的最小值,越界会回弹
     78         this.max = option.max;    // 不必需,运动属性的最大值,越界会回弹, 一般为0
     79         this.deceleration = 0.0006;    // 减速系数
     80         this.maxRegion = this._getValue(option.maxRegion, 600);    // 最大区域, 默认60
     81         this.springMaxRegion = this._getValue(option.springMaxRegion, 60);    // 弹动的最大值区域, 默认60
     82         this.maxSpeed = option.maxSpeed;    // 最大速度
     83         this.hasMaxSpeed = !(this.maxSpeed === undefined);    // 是否有最大速度属性
     84         this.lockDirection = this._getValue(option.lockDirection, true);    // 锁定方向
     85 
     86         var noop = function () { };    // 空函数
     87         this.touchStart = option.touchStart || noop;
     88         this.change = option.change || noop;
     89         this.touchMove = option.touchMove || noop;
     90         this.pressMove = option.pressMove || noop;
     91         this.tap = option.tap || noop;
     92         this.touchEnd = option.touchEnd || noop;
     93         this.touchCancel = option.touchCancel || noop;
     94         this.reboundEnd = option.reboundEnd || noop;    // 回弹回调
     95         this.animationEnd = option.animationEnd || noop;
     96         this.correctionEnd = option.correctionEnd || noop;    // 修改回调
     97 
     98         this.preventDefault = this._getValue(option.preventDefault, true);    // 默认是true,是否阻止默认事件
     99         this.preventDefaultException = { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ };    // 这几个tag标签,阻止默认事件例外
    100         this.hasMin = !(this.min === undefined);    // 是否有min,和max属性
    101         this.hasMax = !(this.max === undefined);
    102         if (this.hasMin && this.hasMax && this.min > this.max) {    // 最小值不能比最大值大啊
    103             throw "the min value can't be greater than the max value."
    104         };
    105         this.isTouchStart = false;    // 触摸是否开始
    106         this.step = option.step;    // 步数(回弹)
    107         this.inertia = this._getValue(option.inertia, true);    // 默认true,开启惯性效果
    108 
    109         this._calculateIndex();    // 添加this.currentPage属性,如果写轮播的话
    110 
    111         this.eventTarget = window;
    112         if(option.bindSelf){
    113             this.eventTarget = this.element;    // 默认touchmove, touchend, touchcancel绑定在 window 上的, 如果option.bindSelf为真值,则绑定到反馈触摸的dom
    114         };
    115 
    116         this._moveHandler = this._move.bind(this);    // 函数赋值
    117         // 反馈触摸的dom只绑定了touchstart(_start), window绑定了 touchmove(_move), touchend(_end), touchcancel(_cancel)方法
    118         bind(this.element, "touchstart", this._start.bind(this));
    119         bind(this.eventTarget, "touchend", this._end.bind(this));
    120         bind(this.eventTarget, "touchcancel", this._cancel.bind(this));
    121         this.eventTarget.addEventListener("touchmove", this._moveHandler, { passive: false, capture: false });    // 使用 passive 改善的滚屏性能
    122         this.x1 = this.x2 = this.y1 = this.y2 = null;    // start时的坐标和move时的坐标
    123     };
    124 
    125     AlloyTouch.prototype = {
    126         _getValue: function (obj, defaultValue) {    // 取用户的值还是使用默认值
    127             return obj === undefined ? defaultValue : obj;
    128         },
    129         _start: function (evt) {
    130             this.isTouchStart = true;    // 触摸开始
    131             this.touchStart.call(this, evt, this.target[this.property]);    // (1. touchStart(evt, propValue)回调)
    132             cancelAnimationFrame(this.tickID);    // 只要触摸就停止动画
    133             this._calculateIndex();    // 重新计算this.currentPage属性值
    134             this.startTime = new Date().getTime();    // 开始的时间戳
    135             this.x1 = this.preX = evt.touches[0].pageX;    // 开始前的坐标保存到x,y 和 preXY去
    136             this.y1 = this.preY = evt.touches[0].pageY;
    137             this.start = this.vertical ? this.preY : this.preX;    // 如果监听竖直方向则取y坐标,否则横向方向取x坐标
    138             this._firstTouchMove = true;    // 开始move(这个条件为_move做铺垫)
    139             this._preventMove = false;    // 不阻止dom继续运动(开启惯性运动之旅的条件之一 哈哈)
    140         },
    141         _move: function (evt) {
    142             if (this.isTouchStart) {    // 触摸开始了
    143                 var len = evt.touches.length,    // 手指数量
    144                     currentX = evt.touches[0].pageX,    // move时的坐标
    145                     currentY = evt.touches[0].pageY;
    146 
    147                 if (this._firstTouchMove && this.lockDirection) {    // 开始move 且 锁定方向 
    148                     var dDis = Math.abs(currentX - this.x1) - Math.abs(currentY - this.y1);    // 是左右滑动还是上下滑动(x>y为水平, y>x为竖直)
    149                     if (dDis > 0 && this.vertical) {    // 左右滑动 且 监听竖直方向
    150                         this._preventMove = true;    // 阻止dom继续运动
    151                     } else if (dDis < 0 && !this.vertical) {    // 竖直滑动 且 监听横向方向
    152                         this._preventMove = true;
    153                     };    // 以上2种情况直接不开启惯性运动之旅(因为左右滑动的话this.vertical需为false,竖直滑动的话this.vertical需为true)
    154                     this._firstTouchMove = false;    // 变成false, 为了手指连续移动中,此方法就不用进来了
    155                 };
    156                 if(!this._preventMove) {    // move时 属性运动(关闭惯性运动后, 其实只有此运动了, 手指移动才会运动, 离开则不会运动了)
    157 
    158                     var d = (this.vertical ? currentY - this.preY : currentX - this.preX) * this.sensitivity;    // 根据竖直还是左右来确定差值 * 灵敏度
    159                     var f = this.moveFactor;    // 变量f的值为 move时的运动系数(默认1)
    160                     if (this.hasMax && this.target[this.property] > this.max && d > 0) {    // 有最大值 且 运动属性值>最大值 且 坐标差值d>0
    161                         f = this.outFactor;
    162                     } else if (this.hasMin && this.target[this.property] < this.min && d < 0) {    // 有最小值 且 运动属性值<最小值 且 坐标差值d<0
    163                         f = this.outFactor;    // 满足以上2中条件 变量f 的值就变成 this.outFactor(默认0.3)
    164                     };
    165                     d *= f;    // 坐标差值再乘以运动系数
    166                     this.preX = currentX;    // 把move时的坐标保存到preXY去
    167                     this.preY = currentY;
    168                     if (!this.fixed) {    // this.fixed默认false(fixed一旦固定了,move时, dom也不会运动)
    169                         this.target[this.property] += d;    //把坐标的差值且乘以运动系数后的结果累加给运动的对象(被transform.js加工后的dom对象)
    170                         // console.log('_move: ' + this.target[this.property]);
    171                     };
    172                     this.change.call(this, this.target[this.property]);    // (2. move时的change(evt, propValue)回调)
    173                     var timestamp = new Date().getTime();    // move时的时间戳
    174                     if (timestamp - this.startTime > 300) {    // move时的时间戳和start时的时间戳大于300的话
    175                         this.startTime = timestamp;    // move时的时间戳赋值给start时的时间戳
    176                         this.start = this.vertical ? this.preY : this.preX;    // 重新计算this.start值
    177                     };
    178                     this.touchMove.call(this, evt, this.target[this.property]);    // (3. touchMove(evt, propValue)回调)
    179                 };
    180 
    181                 if (this.preventDefault && !preventDefaultTest(evt.target, this.preventDefaultException)) {    //阻止默认事件除了INPUT|TEXTAREA|BUTTON|SELECT这几个标签
    182                     evt.preventDefault();
    183                 };
    184 
    185                 if (len === 1) {    // 一根手指
    186                     if (this.x2 !== null) {    //一开始为null
    187                         evt.deltaX = currentX - this.x2;    // move移动时的差值
    188                         evt.deltaY = currentY - this.y2;
    189 
    190                     } else {
    191                         evt.deltaX = 0;    // 一开始差值为0啦
    192                         evt.deltaY = 0;
    193                     }
    194                     this.pressMove.call(this, evt, this.target[this.property]);    // (4. pressMove(evt, propValue)回调)
    195                 }
    196                 this.x2 = currentX;    //把本次坐标赋值给x2,y2
    197                 this.y2 = currentY;
    198             }
    199         },
    200         _end: function (evt) {
    201             if (this.isTouchStart) {    // 触摸开始了
    202 
    203                 this.isTouchStart = false;    // 触摸开始变量置为false(_move方法进不去了)
    204                 var self = this,    // 存个实例
    205                     current = this.target[this.property],    // 当前运动对象的运动属性的值
    206                     triggerTap = (Math.abs(evt.changedTouches[0].pageX - this.x1) < 30 && Math.abs(evt.changedTouches[0].pageY - this.y1) < 30);    // 是否触发tap事件回调
    207                 if (triggerTap) {    // 触发tap事件
    208                     this.tap.call(this, evt, current);    // (5. tap(evt, propValue)回调)
    209                 };
    210 
    211                 if (this.touchEnd.call(this, evt, current, this.currentPage) === false) return;    // (6. touchEnd(evt, propValue, 当前第几页)回调)这个主要给轮播用的吧
    212 
    213                 if (this.hasMax && current > this.max) {    // 有最大值 且 当前运动对象的运动属性的值大于最大值
    214 
    215                     this._to(this.max, 200, ease, this.change, function (value) {    // (最大小值, time, 曲线, change函数, fn)
    216                         this.reboundEnd.call(this, value);
    217                         this.animationEnd.call(this, value);
    218                     }.bind(this));
    219 
    220                 } else if (this.hasMin && current < this.min) {    // 有最小值 且 当前运动对象的运动属性的值小于最小值
    221 
    222                     this._to(this.min, 200, ease, this.change, function (value) {
    223                         this.reboundEnd.call(this, value);
    224                         this.animationEnd.call(this, value);
    225                     }.bind(this));
    226 
    227                 } else if (this.inertia && !triggerTap && !this._preventMove) {    // 开启惯性效果(默认为true) 且 不触发tap事件 且 this._preventMove为false;
    228 
    229                     var dt = new Date().getTime() - this.startTime;    // _end时的时间戳和_move时的时间戳的差值
    230                     if (dt < 300) {    // 小于300ms就执行惯性运动
    231                         var distance = ((this.vertical ? evt.changedTouches[0].pageY : evt.changedTouches[0].pageX) - this.start) * this.sensitivity,    // _end中的坐标与_move中坐标的差值乘以灵敏度
    232                             speed = Math.abs(distance) / dt,    // 速度为坐标差值/时间戳差值
    233                             speed2 = this.factor * speed;    // 速度2为 系数(默认1)乘以速度
    234                         if(this.hasMaxSpeed && speed2 > this.maxSpeed) {    // 有最大速度 且 速度2大于最大速度
    235                             speed2 = this.maxSpeed;    // 速度2就为最大速度
    236                         };
    237 
    238                         // 目标值destination = 当前运动对象的运动属性的值 + (速度2*速度2)/(2*减速系数)*(-1||1); 
    239                         var destination = current + (speed2 * speed2) / (2 * this.deceleration) * (distance < 0 ? -1 : 1); 
    240                         // console.log('distance: '+ distance);
    241                         // console.log('目标值destination: '+ destination);
    242                         // console.log('差值: '+ destination > current);
    243 
    244                         var tRatio = 1;    // 比例
    245                         if (destination < this.min ) {    // 目标值 比 最小值 小
    246                             if (destination < this.min - this.maxRegion) {
    247                                 tRatio = reverseEase((current - this.min + this.springMaxRegion) / (current - destination));
    248                                 destination = this.min - this.springMaxRegion;
    249                             } else {
    250                                 tRatio = reverseEase((current - this.min + this.springMaxRegion * (this.min - destination) / this.maxRegion) / (current - destination));
    251                                 destination = this.min - this.springMaxRegion * (this.min - destination) / this.maxRegion;
    252                             }
    253                         } else if (destination > this.max) {    // 目标值 比 最大值 大
    254                             if (destination > this.max + this.maxRegion) {
    255                                 tRatio = reverseEase((this.max + this.springMaxRegion - current) / (destination - current));
    256                                 destination = this.max + this.springMaxRegion;
    257                             } else {
    258                                 tRatio = reverseEase((this.max + this.springMaxRegion * ( destination-this.max) / this.maxRegion - current) / (destination - current));
    259                                 destination = this.max + this.springMaxRegion * (destination - this.max) / this.maxRegion;
    260                                 
    261                             }
    262                         };
    263 
    264                         // 持续时间duration = 数字舍入(速度/减速系数) * 比例;
    265                         var duration = Math.round(speed / self.deceleration) * tRatio;
    266                         // console.log('持续时间duration: ' + duration);
    267 
    268                         // end方法计算好的目标值和持续时间传入_to方法,运动起来吧
    269                         self._to(Math.round(destination), duration, ease, self.change, function (value) {    // 回调函数的value 就是 destination
    270 
    271                             if (self.hasMax && self.target[self.property] > self.max) {    // 有最大值 且 运动属性的值大于最大值
    272 
    273                                 cancelAnimationFrame(self.tickID);
    274                                 self._to(self.max, 600, ease, self.change, self.animationEnd);
    275 
    276                             } else if (self.hasMin && self.target[self.property] < self.min) {    // 有最小值 且 运动属性的值小于最小值
    277 
    278                                 cancelAnimationFrame(self.tickID);
    279                                 self._to(self.min, 600, ease, self.change, self.animationEnd);
    280 
    281                             } else {
    282                                 self._correction();    // 回弹
    283                             };
    284 
    285                             self.change.call(this, value);    // (7. change(运动属性的值)回调函数)
    286                         });
    287                     } else {
    288                         self._correction();    // 回弹
    289                     }
    290                 } else {
    291                     self._correction();    // 回弹
    292                 };
    293 
    294                 // 阻止默认事件
    295                 if (this.preventDefault && !preventDefaultTest(evt.target, this.preventDefaultException)) {
    296                     evt.preventDefault();
    297                 };
    298 
    299             };
    300             // 坐标置null
    301             this.x1 = this.x2 = this.y1 = this.y2 = null;
    302         },
    303         // 提供目标值, 持续时间, 然后根据时间戳和time持续时间的差值比较, 时间戳< time的话就一直调用动画,否则结束
    304         _to: function (value, time, ease, onChange, onEnd) {    // value:目标值, time:持续时间, ease: 曲线动画, onChange: this.change回调函数(用户的), onEnd回调
    305             if (this.fixed) return;    // fixed(默认false)有真值就return掉
    306             var el = this.target,    // 运动的对象
    307                 property = this.property;    // 运动的属性
    308             var current = el[property];    // 运动对象运动属性当前的值
    309             var dv = value - current;    // 目标值与当前属性的差值
    310             var beginTime = new Date();    // 开始时间戳
    311             var self = this;    // 存个实例
    312             var toTick = function () {
    313 
    314                 var dt = new Date() - beginTime;    // 时间戳差值
    315                 if (dt >= time) {    // 时间戳差值大于持续时间
    316                     el[property] = value;    // 把目标值赋值给dom属性
    317                     onChange && onChange.call(self, value);    // (7. change(目标值)回调函数)
    318                     onEnd && onEnd.call(self, value);    // onEnd回调
    319                     return;
    320                 };
    321                 el[property] = dv * ease(dt / time) + current;
    322                 // console.log(el[property]);
    323                 self.tickID = requestAnimationFrame(toTick);    // 动画自调用
    324                 onChange && onChange.call(self, el[property]);    //(7. change(属性值)回调函数)
    325             };
    326             toTick();    // 调用
    327         },
    328         // 该函数用来当动画完成后根据this.step修正一点(回弹效果)
    329         _correction: function () {
    330             if (this.step === undefined) return;    // step没赋值的话就return掉
    331             var el = this.target,    // 运动的对象
    332                 property = this.property;    // 运动对象的运动属性
    333             var value = el[property];    // 运动对象运动属性的值
    334             var rpt = Math.floor(Math.abs(value / this.step));    // 向下取整(取绝对值(运动对象运动属性的值/ this.step值))
    335             var dy = value % this.step;    // 运动对象运动属性的值取余数
    336 
    337             if (Math.abs(dy) > this.step / 2) {    // 我想这里又应用了啥物理原理根据条件判断,来计算value目标值的,然后调用_to方法执行惯性运动
    338                 this._to((value < 0 ? -1 : 1) * (rpt + 1) * this.step, 400, ease, this.change, function (value) {
    339                     this._calculateIndex();
    340                     this.correctionEnd.call(this, value);
    341                     this.animationEnd.call(this, value);
    342                 }.bind(this));
    343             } else {
    344                 this._to((value < 0 ? -1 : 1) * rpt * this.step, 400, ease, this.change, function (value) {
    345                     this._calculateIndex();    // 重新计算this.currentPage值
    346                     this.correctionEnd.call(this, value);    // (8. correctionEnd(属性值)回调函数)
    347                     this.animationEnd.call(this, value);    // (9. animationEnd(属性值)回调函数)
    348                 }.bind(this));
    349             }
    350         },
    351         _cancel: function (evt) {
    352             var current = this.target[this.property];
    353             this.touchCancel.call(this, evt, current);
    354             this._end(evt);
    355         },
    356         // 给用户使用的, 控制dom以不同的曲线动画运动
    357         to: function (v, time, user_ease) {
    358             this._to(v, this._getValue(time, 600), user_ease || ease, this.change, function (value) {
    359                 this._calculateIndex();
    360                 this.reboundEnd.call(this, value);    // (10. reboundEnd(属性值)回调函数)
    361                 this.animationEnd.call(this, value);    // (9. animationEnd(属性值)回调函数)
    362             }.bind(this));
    363 
    364         },
    365         // 计算this.currentPage值
    366         _calculateIndex: function () {
    367             if (this.hasMax && this.hasMin) {
    368                 this.currentPage = Math.round((this.max - this.target[this.property]) / this.step);    // 当前第几页,比如轮播图的第几个,从0开始
    369             }
    370         }
    371         
    372     };
    373 
    374     // 抛出去
    375     if (typeof module !== 'undefined' && typeof exports === 'object') {
    376         module.exports = AlloyTouch;
    377     } else {
    378         window.AlloyTouch = AlloyTouch;
    379     };
    380 
    381 })();

    使用姿势:(由于此库比较抽象,使用姿势需要根据需求来使用,以下提供了3个demo的使用姿势,基本差不多,可以用手机扫二维码看看(由于编写html页面时,没考虑手机屏幕的适应,所以凑合这点吧,哈哈))

      1         // es5 语法
      2         // 列表加载更多
      3         var List = function() {
      4             this.list_Target = document.querySelector("#list_target");
      5             this.Ul = this.list_Target.children[0];
      6             this.oList = document.querySelector("#list");
      7             //给element注入transform属性
      8             Transform(this.list_Target);
      9 
     10             this.at = null;
     11             this.loading = false;
     12             this.index = 21;
     13         };
     14 
     15         Object.assign(List.prototype, {
     16             init: function() {
     17                 var self = this;
     18                 this.at = new AlloyTouch({
     19                     touch: '#list',//反馈触摸的dom
     20                     vertical: true,//不必需,默认是true代表监听竖直方向touch
     21                     target: this.list_Target, //运动的对象
     22                     property: "translateY",  //被滚动的属性
     23                     factor: 1,//不必需,默认值是1代表touch区域的1px的对应target.y的1
     24                     inertia: true,
     25                     min: this.oList.offsetHeight - this.list_Target.offsetHeight, //不必需,滚动属性的最小值
     26                     max: 0, //不必需,滚动属性的最大值
     27                     step: 2,
     28                     touchStart: function() {
     29                         self.getMin();
     30                     },
     31                     change: function(v) {
     32                         // console.log(v);
     33                         if (v < this.min && !self.loading) {
     34                             self.loading = true;
     35                             self.loadMore();
     36                         };
     37                     }
     38                 });
     39             },
     40             getMin: function() {
     41                 this.at.min = -parseInt(getComputedStyle(this.list_Target).height) + this.oList.offsetHeight;
     42             },
     43             loadMore: function() {
     44                 setTimeout(function() {
     45                     this.loading = false;
     46                     var Oli = null,
     47                         i = 0,
     48                         len = 20;
     49 
     50                     for (; i < len; i ++) {
     51                         this.index += 1;
     52                         Oli = document.createElement('li');
     53                         Oli.innerHTML = this.index;
     54                         this.Ul.appendChild(Oli);     // 这里测试,不推荐这么写啊, 太消耗性能了
     55                     };
     56 
     57                     this.getMin();
     58                 }.bind(this), 500);
     59             }
     60         });
     61 
     62         new List().init();
     63 
     64         // es6 语法 
     65         /*let flower = (new class {
     66             constructor() {
     67                 this.at = null;
     68                 this.target = this.$('testImg');
     69                 Transform(this.target);
     70             }
     71 
     72             $(id) {
     73                 return document.querySelector('#' + id);
     74             }
     75 
     76             init() {
     77                 this.at = new AlloyTouch({
     78                     touch: this.target,//反馈触摸的dom
     79                     vertical: false,//不必需,默认是true代表监听竖直方向touch
     80                     target: this.target, //运动的对象
     81                     property: "rotateY",  //被滚动的属性
     82                     factor: 1,//不必需,默认值是1代表touch区域的1px的对应target.y的1
     83                     inertia: true,
     84                     step: 100
     85                 });
     86             }
     87         }).init();*/
     88 
     89 
     90         // 花朵
     91         var flower = function() {
     92             
     93             var target = $('testImg');
     94             Transform(target);
     95 
     96             function $(id) {
     97                 return document.querySelector('#' + id);
     98             };
     99 
    100             return function() {
    101                 return new AlloyTouch({
    102                     touch: target,//反馈触摸的dom
    103                     vertical: false,//不必需,默认是true代表监听竖直方向touch
    104                     target: target, //运动的对象
    105                     property: "rotateY",  //被滚动的属性
    106                     factor: 1,//不必需,默认值是1代表touch区域的1px的对应target.y的1
    107                     inertia: true,
    108                     step: 100
    109                 });
    110             };
    111         }()();
    112         
    113 
    114         // 轮播
    115         var carousel = function() {
    116             var scroller = document.querySelector('#carousel_scroller');
    117             Transform(scroller);
    118             var aA = document.querySelectorAll('#nav a');
    119             var at = null;
    120             var tickId = null;
    121 
    122             function init() {
    123                 at = new AlloyTouch({
    124                     touch: '#carousel_container',
    125                     target: scroller,
    126                     vertical: false,
    127                     property: 'translateX',
    128                     step: window.innerWidth,
    129                     max: 0,
    130                     min: - window.innerWidth * 3,
    131                     touchStart: function() {
    132                         clearInterval(tickId);
    133                     },
    134                     touchEnd: function(evt, v, index) {
    135                         var value = -(this.step * index);
    136                         var dt = v - value;
    137                         console.log(dt);
    138 
    139                         if (v > this.max) {    // 属性值大于最大值取最大值
    140                             this.to(this.max);
    141                         } else if (v < this.min) {    // 属性值小于最小值取最小值
    142                             this.to(this.min);
    143                         } else if (Math.abs(dt) < 30) {    // 2边空隙小于30就回到当前值
    144                             this.to(value);
    145                         } else if (dt > 0) {    // 大于0往右边滚动一个
    146                             this.to(value + this.step);
    147                         } else {    // 小于0就往左边滚动一个
    148                             this.to(value - this.step);
    149                         };
    150                         loop();
    151                         return false;
    152                     },
    153                     animationEnd: function(evt, v) {
    154                         Array.prototype.slice.call(aA).forEach(function(item, index) {
    155                             item.className = '';
    156                         });
    157                         aA[this.currentPage].className = 'active';
    158                     }
    159                 });
    160             };
    161 
    162             // 循环播放
    163             function loop() {
    164                 tickId = setInterval(function() {
    165                     this.currentPage += 1;
    166                     if (this.currentPage > 3) {
    167                         this.currentPage = 0;
    168                     };
    169                     this.to(-(this.currentPage * this.step));
    170                 }.bind(at), 2000);
    171             };
    172 
    173             return {
    174                 init: init,
    175                 loop: loop
    176             };
    177         }();
    178         carousel.init();
    179         carousel.loop();

    我觉得还是用手机体验一把alloyTouch的灵活和强大吧,手机对准扫一扫吧。

    3个关于alloyTouch的小demo。

     更多demo,请去github看看。

    ps: 

    此库还是很有用的,很喜欢。
    github: https://github.com/AlloyTeam/AlloyTouch

    开心的做一个无忧无虑的码农,争取每天进步一点。
  • 相关阅读:
    outlook的签名导致新邮件使用签名时产生ActiveX警告。
    Insecure.Org 2006年度的安全工具调查
    理解windows网络/netbios/SMB/CIFS
    hp 笔记本 sata native mode安装xp
    repadmin查看活动目录内的对象属性
    Schema Object Identifiers OIDs
    普通用户设置显示DPI没有权限
    在两个页面间翻转设置Animation动作的一些总结
    Xcode3.2.6异常调试,快速定位出错行
    (转)用NSDateFormatter调整时间格式的代码
  • 原文地址:https://www.cnblogs.com/sorrowx/p/6531273.html
Copyright © 2011-2022 走看看