zepto.js中的Touch事件

  在移動端常常須要處理滑動事件,好比banner圖的左滑右滑,都須要事件響應,這在PC端是沒有這類事件的。而在zepto.js中,下載下來的代碼也並無自動加上對這類事件的支持,可是有提供相應的模塊,須要你本身加上去(下表中最後一個touch模塊):javascript

module default description
zepto 核心模塊;包含許多方法
event 經過on()off()處理事件
ajax XMLHttpRequest 和 JSONP 實用功能
form 序列化 & 提交web表單
ie 增長支持桌面的Internet Explorer 10+和Windows Phone 8。
detect   提供 $.os和 $.browser消息
fx   The animate()方法
fx_methods   以動畫形式的 showhidetoggle, 和 fade*()方法.
assets   實驗性支持從DOM中移除image元素後清理iOS的內存。
data   一個全面的 data()方法, 可以在內存中存儲任意對象。
deferred   提供 $.Deferredpromises API. 依賴"callbacks" 模塊. 
當包含這個模塊時候, $.ajax() 支持promise接口鏈式的回調。
callbacks   爲"deferred"模塊提供 $.Callbacks
selector   實驗性的支持 jQuery CSS 表達式 實用功能,好比 $('div:first')el.is(':visible')
touch   在觸摸設備上觸發tap– 和 swipe– 相關事件。這適用於全部的`touch`(iOS, Android)和`pointer`事件(Windows Phone)。

  這些模塊的代碼能夠直接加在zepto.js的最底部,像拼積木同樣,選擇模塊而後加上去拼合一份適合本身項目的增強版zepto.js。css

  關於代碼中是如何實現的事件這裏不作過多解讀,核心確定是經過touch座標的差值判斷究竟是左滑仍是上滑。這裏主要講的是touch模塊中的一個坑,那就是會和國內的主流手機瀏覽器的默認事件衝突。具體表現就是,給一個元素綁定左滑動後,在UC瀏覽器中滑動該元素會出現頁面被切換的狀況。java

  簡單的測試發現:UC/QQ都與touch事件發生衝突,安卓自帶瀏覽器和谷歌瀏覽器不會有此現象。touch這個腳本原本就是外國人寫的,固然就無視中國特點了。這裏對touch作了一些簡單的修改,達到避免這種衝突發生。jquery

  首先引入zepto(已包含touch)以後,代碼以下:  git

$('#div').swipeLeft(function(e){
     alert(1);	  	 
})

  在PC上用谷歌開發工具模擬器看,沒有任何問題。github

  在手機上用UC或者QQ看,悲催了,頁面直接被滑跑了。你能夠試試,體驗一下總比別人告訴你印象深入。web

  很明顯,這裏須要阻止默認事件,好比這樣改一改:  ajax

$('#div').on('touchstart',function(e){
   e.preventDefault();
}).swipeLeft(function(e){
   alert(1);	  	 
})

  手機上即可以彈出1。而後事情並無結束。api

  首先這樣寫太醜陋了,每一個swipe以前都要去阻止默認事件,更加難以接受的是,這個時候我上下滑動該元素也會阻止默認事件,也就意味着,當頁面須要正常上下滾動的時候,手指在該元素上將滑動不了!promise

  好吧,那我就去改touch。

  首先,找到touch事件快捷綁定的代碼塊:  

;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){
    $.fn[m] = function(callback){  
      return this.bind(m, callback) 
    }
})

  修改以下:

;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){
    $.fn[m] = function(callback){  
      if(!this.data('swipeEvents')){
        this.data('swipeEvents',m);
      }else{
        this.data('swipeEvents',this.data('swipeEvents')+'|'+m);
      }       
      return this.bind(m, callback) 
    }
})

  目的:給全部直接調用swipe的元素,默默的標識上一個數據,該數據就是本元素被綁定的swipe事件的名稱,綁定多個swipe時以 | 隔開。

  第二步:找到給body綁定的事件冒泡的touchmove事件代碼:

.bind('touchmove', function(e){
      cancelLongTap()
      touch.x2 = e.touches[0].pageX
      touch.y2 = e.touches[0].pageY
})

  修改成:

.bind('touchmove', function(e){
      cancelLongTap()
      touch.x2 = e.touches[0].pageX
      touch.y2 = e.touches[0].pageY
      
      if(touch.el&&touch.el.data('swipeEvents')){  
        if(Math.abs(touch.x2-touch.x1)>4&&/Left|Right/.test(touch.el.data('swipeEvents'))){
          e.preventDefault();
        }else if(Math.abs(touch.y2-touch.y1)>4&&/Up|Down/.test(touch.el.data('swipeEvents'))){
          e.preventDefault();
        }
      }      
 })

  目的:只要該元素綁定了swipe事件,而且滑動軌跡和swipe事件匹配上,則阻止默認事件。這樣,匹配不上的將不被阻止,好比你只是綁定的左右滑動,當touch是上下滑動的時候,不會執行到preventDefault。

  通過UC和QQ測試都沒有問題。

  可是,事情仍是沒有結束。由於,你只要換個方式綁定swipe就掛了,好比這樣子:  

$('#div').on('swipeLeft',function(e){

  由於咱們只給$.fn[swipe]的時候作了處理,也就是元素直接調用siwpe方法時,纔會有效,一旦調用on方法就嗝屁了。固然,通常元素直接調用swipe就能夠了,可是若是想用到事件委託,給大量元素批量綁定的時候就必須用到on啊,這怎麼辦?很差意思,我這裏沒有給出好辦法,由於on這個方法很差改也不能改,改touch已是心驚膽戰了,直接改zepto水平不夠。因此暫時還沒想到最好的辦法,誰知道完美解決辦法的請留言。

相關文章
相關標籤/搜索