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.htmlhtml

  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
相關文章
相關標籤/搜索