在移動端常常須要處理滑動事件,好比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 | 以動畫形式的 show , hide , toggle , 和 fade*() 方法. |
|
assets | 實驗性支持從DOM中移除image元素後清理iOS的內存。 | |
data | 一個全面的 data() 方法, 可以在內存中存儲任意對象。 |
|
deferred | 提供 $.Deferred promises 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水平不夠。因此暫時還沒想到最好的辦法,誰知道完美解決辦法的請留言。