• 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

    开心的做一个无忧无虑的码农,争取每天进步一点。
  • 相关阅读:
    解释机器学习模型的一些方法(一)——数据可视化
    机器学习模型解释工具-Lime
    Hive SQL 语法学习与实践
    LeetCode 198. 打家劫舍(House Robber)LeetCode 213. 打家劫舍 II(House Robber II)
    LeetCode 148. 排序链表(Sort List)
    LeetCode 18. 四数之和(4Sum)
    LeetCode 12. 整数转罗马数字(Integer to Roman)
    LeetCode 31. 下一个排列(Next Permutation)
    LeetCode 168. Excel表列名称(Excel Sheet Column Title)
    论FPGA建模,与面向对象编程的相似性
  • 原文地址:https://www.cnblogs.com/sorrowx/p/6531273.html
Copyright © 2020-2023  润新知