• zepto 的 touch.js库(修复BUG,让滑动更灵活)


    最近在做一个手机版的项目,而做手机网页,那么就会考虑到用轻量级库,用jquery的话,会比较庞大,而我们就选用 zepto.js 来做开发,可是在开发的时候要用到手势事件(比如左右滑动,上下滑动),于是就在网上查了一下 zepto.js 的官网,发现有 touch 事件来模拟手势事件,这个开发就会带来便利,而不用去写JS底层代码;在网上搜罗了一下 zepto.js touch 库,找到了不多 touch.js 的相关信息,真的感觉很少(不知道是不是zepto.js不成熟的表现),终于在网上搜罗到了一个外国人写的 touch.js 库,然后就用在了项目上,但是在用到的时候,发现 swipeLeft ,swipeRight 这些事件会有一些 bug 而且不灵活,最后又在网上搜罗了一个国人修改的,但是最后用起来还是不咋滴(敏感度有点差),最后在群里问问大神们,发现有个高手他说他自己写了一个库,于是乎我就跟他聊了几下,然后他告诉他的代码放在了  github 上,那么我就上去抄了下来,用在了项目上,顿时感觉手势事件灵活了,不错,真心不错,还是得谢谢那个哥们,好了,说了那么多就上代码吧,把这个库压缩一下,引用在项目上就可以使用 swipeLeft,swipeRight 这些事件了,由于本人只用了向左向右的滑动事件,就没有测试向上向下滑动了,如果使用过这些事件的童鞋,也可以告诉我,让我也好知道一下 ^_^...   使用方法,请查看这位高手的博客  https://github.com/bh-lay/toucher/blob/master/touch.html

      1 ;(function(global,doc,factoryFn){
      2     //初始化toucher主方法
      3     var factory = factoryFn(global,doc);
      4     
      5     //提供window.util.toucher()接口
      6     global.util = global.util || {};
      7     global.util.toucher = global.util.toucher || factory;
      8     
      9     //提供CommonJS规范的接口
     10     global.define && define(function(require,exports,module){
     11         //对外接口
     12         return factory;
     13     });
     14 })(this,document,function(window,document){
     15     /**
     16      * 判断是否拥有某个class
     17      */
     18     function hasClass(dom,classSingle){
     19         return dom.className.match(new RegExp('(\s|^)' + classSingle +'(\s|$)'));
     20     }
     21 
     22     /**
     23      * @method 向句柄所在对象增加事件监听
     24      * @description 支持链式调用
     25      * 
     26      * @param string 事件名
     27      * @param [string] 事件委托至某个class(可选)
     28      * @param function 符合条件的事件被触发时需要执行的回调函数 
     29      * 
     30      */
     31     function ON(eventStr,a,b){
     32         this._events = this._events || {};
     33         var className,fn;
     34         if(typeof(a) == 'string'){
     35             className = a.replace(/^./,'');
     36             fn = b;
     37         }else{
     38             className = null;
     39             fn = a;
     40         }
     41         //检测callback是否合法,事件名参数是否存在·
     42         if(typeof(fn) == 'function' && eventStr && eventStr.length){
     43             var eventNames = eventStr.split(/s+/);
     44             for(var i=0,total=eventNames.length;i<total;i++){
     45             
     46                 var eventName = eventNames[i];
     47                 //事件堆无该事件,创建一个事件堆
     48                 if(!this._events[eventName]){
     49                     this._events[eventName] = [];
     50                 }
     51                 this._events[eventName].push({
     52                     'className' : className,
     53                     'fn' : fn
     54                 });
     55             }
     56         }
     57 
     58         //提供链式调用的支持
     59         return this;
     60     }
     61 
     62     /**
     63      * @method 事件触发器
     64      * @description 根据事件最原始被触发的target,逐级向上追溯事件绑定
     65      * 
     66      * @param string 事件名
     67      * @param object 原生事件对象
     68      */
     69     function EMIT(eventName,e){
     70         this._events = this._events || {};
     71         //事件堆无该事件,结束触发
     72         if(!this._events[eventName]){
     73             return
     74         }
     75         //记录尚未被执行掉的事件绑定
     76         var rest_events = this._events[eventName];
     77         
     78         //从事件源:target开始向上冒泡
     79         var target = e.target;
     80         while (1) {
     81             //若没有需要执行的事件,结束冒泡
     82             if(rest_events.length ==0){
     83                 return;
     84             }
     85             //若已经冒泡至顶,检测顶级绑定,结束冒泡
     86             if(target == this.dom || !target){
     87                 //遍历剩余所有事件绑定
     88                 for(var i=0,total=rest_events.length;i<total;i++){
     89                     var classStr = rest_events[i]['className'];
     90                     var callback = rest_events[i]['fn'];
     91                     //未指定事件委托,直接执行
     92                     if(classStr == null){
     93                         event_callback(eventName,callback,target,e);
     94                     }
     95                 }
     96                 return;
     97             }
     98             
     99             //当前需要校验的事件集
    100             var eventsList = rest_events;
    101             //置空尚未执行掉的事件集
    102             rest_events = [];
    103 
    104             //遍历事件所有绑定
    105             for(var i=0,total=eventsList.length;i<total;i++){
    106                 var classStr = eventsList[i]['className'];
    107                 var callback = eventsList[i]['fn'];
    108                 //符合事件委托,执行
    109                 if(hasClass(target,classStr)){
    110                     //返回false停止事件冒泡及后续事件,其余继续执行
    111                     if(event_callback(eventName,callback,target,e) == false){
    112                         return
    113                     }
    114                 }else{
    115                     //不符合执行条件,压回到尚未执行掉的列表中
    116                     rest_events.push(eventsList[i]);
    117                 }
    118             }
    119             //向上冒泡
    120             target = target.parentNode;
    121         }
    122     }
    123     
    124     /**
    125      * 执行绑定的回调函数,并创建一个事件对象
    126      * @param[string]事件名
    127      * @param[function]被执行掉的函数
    128      * @param[object]指向的dom
    129      * @param[object]原生event对象
    130      */
    131     function event_callback(name,fn,dom,e){
    132         var touch = e.touches.length ? e.touches[0] : {};
    133         
    134         var newE = {
    135             'type' : name,
    136             'target' : e.target,
    137             'pageX' : touch.clientX || 0,
    138             'pageY' : touch.clientY || 0
    139         };
    140         //为swipe事件增加交互初始位置及移动距离
    141         if(name == 'swipe' && e.startPosition){
    142             newE.startX = e.startPosition['pageX'],
    143             newE.startY = e.startPosition['pageY'],
    144             newE.moveX = newE.pageX - newE.startX,
    145             newE.moveY = newE.pageY - newE.startY
    146         }
    147         var call_result = fn.call(dom,newE);
    148         //若绑定方法返回false,阻止浏览器默认事件
    149         if(call_result == false){
    150             e.preventDefault();
    151             e.stopPropagation();
    152         }
    153         
    154         return call_result;
    155     }
    156     /**
    157      * 判断swipe方向
    158      */
    159     function swipeDirection(x1, x2, y1, y2) {
    160         return Math.abs(x1 - x2) >=
    161             Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
    162     }
    163 
    164     /**
    165      * 监听原生的事件,主动触发模拟事件
    166      * 
    167      */
    168     function eventListener(DOM){
    169         var this_touch = this;
    170 
    171         //轻击开始时间
    172         var touchStartTime = 0;
    173         
    174         //记录上一次点击时间
    175         var lastTouchTime = 0;
    176         
    177         //记录初始轻击的位置
    178         var x1,y1,x2,y2;
    179         
    180         //轻击事件的延时器
    181         var touchDelay;
    182         
    183         //测试长按事件的延时器
    184         var longTap;
    185         
    186         //记录当前事件是否已为等待结束的状态
    187         var isActive = false;
    188         //记录有坐标信息的事件
    189         var eventMark = null;
    190         //单次用户操作结束
    191         function actionOver(e){
    192             isActive = false;
    193             clearTimeout(longTap);
    194             clearTimeout(touchDelay);
    195         }
    196         
    197         //触屏开始
    198         function touchStart(e){
    199             //缓存事件
    200             eventMark = e;
    201         
    202             x1 = e.touches[0].pageX;
    203             y1 = e.touches[0].pageY;
    204             x2 = 0;
    205             y2 = 0;
    206             isActive = true;
    207             touchStartTime = new Date();
    208             EMIT.call(this_touch,'swipeStart',e);
    209             //检测是否为长按
    210             clearTimeout(longTap);
    211             longTap = setTimeout(function(){
    212                 actionOver(e);
    213                 //断定此次事件为长按事件
    214                 EMIT.call(this_touch,'longTap',e);
    215             },500);
    216         }
    217         //触屏结束
    218         function touchend(e){
    219             //touchend中,拿不到坐标位置信息,故使用全局保存下的事件
    220             EMIT.call(this_touch,'swipeEnd',eventMark);
    221             if(!isActive){
    222                 return
    223             }
    224             var now = new Date();
    225             if(now - lastTouchTime > 260){
    226                 touchDelay = setTimeout(function(){
    227                     //断定此次事件为轻击事件
    228                     actionOver();
    229                     EMIT.call(this_touch,'singleTap',eventMark);
    230                 },250);
    231             }else{
    232                 clearTimeout(touchDelay);
    233                 actionOver(e);
    234                 //断定此次事件为连续两次轻击事件
    235                 EMIT.call(this_touch,'doubleTap',eventMark);
    236             }
    237             lastTouchTime = now;
    238         }
    239         
    240         //手指移动
    241         function touchmove(e){
    242             //缓存事件
    243             eventMark = e;
    244             //在原生事件基础上记录初始位置(为swipe事件增加参数传递)
    245             e.startPosition = {
    246                 'pageX' : x1,
    247                 'pageY' : y1
    248             };
    249             //断定此次事件为移动事件
    250             EMIT.call(this_touch,'swipe',e);
    251 
    252             if(!isActive){
    253                 return
    254             }
    255            x2 = e.touches[0].pageX
    256             y2 = e.touches[0].pageY
    257             if(Math.abs(x1-x2)>2 || Math.abs(y1-y2)>2){
    258                 //断定此次事件为移动手势
    259                 var direction = swipeDirection(x1, x2, y1, y2);
    260                 EMIT.call(this_touch,'swipe' + direction,e);
    261             }else{
    262                 //断定此次事件为轻击事件
    263                 actionOver(e);
    264                 EMIT.call(this_touch,'singleTap',e);
    265             }
    266             actionOver(e);
    267         }
    268 
    269         /**
    270          * 对开始手势的监听
    271          */
    272         DOM.addEventListener('touchstart',touchStart);
    273         DOM.addEventListener('MSPointerDown',touchStart);
    274         DOM.addEventListener('pointerdown',touchStart);
    275 
    276         /**
    277          * 对手势结束的监听(轻击)
    278          */
    279         DOM.addEventListener('touchend',touchend);
    280         DOM.addEventListener('MSPointerUp',touchend);
    281         DOM.addEventListener('pointerup',touchend);
    282 
    283         /**
    284          * 对移动手势的监听
    285          */
    286         DOM.addEventListener('touchmove',touchmove);
    287         DOM.addEventListener('MSPointerMove',touchmove);
    288         DOM.addEventListener('pointermove',touchmove);
    289 
    290         /**
    291          * 对移动结束的监听
    292          */
    293         DOM.addEventListener('touchcancel',actionOver);
    294         DOM.addEventListener('MSPointerCancel',actionOver);
    295         DOM.addEventListener('pointercancel',actionOver);
    296     }
    297     
    298     /**
    299      * touch类
    300      * 
    301      */
    302     function touch(DOM,param){
    303         var param = param || {};
    304 
    305         this.dom = DOM;
    306         //监听DOM原生事件
    307         eventListener.call(this,this.dom);
    308     }
    309     //拓展事件绑定方法
    310     touch.prototype['on'] = ON;
    311     
    312     //对外提供接口
    313     return function (dom){
    314         return new touch(dom);
    315     };
    316 });
    View Code
  • 相关阅读:
    同步与异步 & 阻塞与非阻塞
    Memcached和Redis比较
    PHP安全之Web攻击
    搭建LNAMP环境(七)- PHP7源码安装Memcached和Memcache拓展
    PHP安装mysql.so扩展
    MySQL基础笔记
    CGI概念
    Nginx与Apache比较
    Nginx重写
    负载均衡session会话保持方法
  • 原文地址:https://www.cnblogs.com/zion0707/p/3947206.html
Copyright © 2020-2023  润新知