安卓webview下使用zepto的swipe遇到的坑

  衆所周知,安卓手機上touch事件一直有各類各樣莫名其妙的問題。html

  好比,我想要用swipeLeft/swipeRight監聽向左向右滑動事件,若是隻是單純爲元素增長swipeLeft/swipeRight事件的話在webview下是不生效的。google了下,仍是有解決方法的。若是這個頁面不須要上下滑動的話,徹底能夠用
$('body').bind("touchmove", function(e) {
     e.preventDefault();
});
解決。即取消body的touchmove默認行爲便可。(爲何取消body的touchmove默認行爲就能讓swipe生效呢?
  但這種作法太絕對太暴力了,若是頁面須要上下滑動的話,那就會出問題。這裏有兩種狀況,第一種是頁面內的某個元素須要上下滑動,另外一種是頁面須要上下滑動。
第一種狀況,只是頁面內某個元素須要上下滑動的話,可爲這個元素監聽touchmove事件,阻止冒泡。好比:
$(id).bind("touchmove", function(e) {
     e.stopPropagation()
});
這樣這個元素就能夠實現上下滑動了。
  那若是是整個頁面須要上下滑動呢?這就比較棘手了。
  我一開始的方案是這樣的。不監聽swipe事件,所有用touch(touchStart/touchmove/touchEnd)實現,在touchStart事件裏獲取點擊時的座標位置(startX, startY),在touchEnd事件裏獲取手指離開時的座標位置(endX, endY)。獲得手指滑動的距離(distanceX , distanceY);
  distanceX = startX - endX;
  distanceY = startY - endY;
  absoluteX = Math.abs(distanceX); //橫向距離絕對值
  absoluteY = Math.abs(distanceY); //縱向距離絕對值
  比較absoluteX和absoluteY的大小,
  absoluteY大則爲上下滑動,不採起任何處理,
  absoluteX大則爲左右滑動,此時再比較startX - endX爲正仍是爲負,正的話則則向左滑動,負的話爲向右滑動。大概代碼爲這樣
var startX, startY;
var endX, endY;
var distanceX, distanceY;
$('body').bind('touchstart', function(event) {
    startX = event.targetTouches[0].clientX;
    startY = event.targetTouches[0].clientY;
}).bind('touchend', function(event) {
    endX = event.changedTouches[0].clientX;
    endY = event.changedTouches[0].clientY;
    distanceX = Math.abs(startX - endX);
    distanceY = Math.abs(startY - endY);
    if (distanceX > distanceY) {
        startX - endX > 0 ? swipeLeft() : swipeRight();
    }
});    
   本覺得這樣應該沒什麼問題了,結果···
  在安卓webview下我模擬的swipe手勢並不會觸發touchend事件,我想這應該也是zepto本身封裝的swipe事件失效的緣由。
  好比,我只點擊了一下屏幕,其實就至關於執行了touchStart,緊接着執行了touchEnd。但若是個人手指在頁面上進行了滑動操做,他就至關於執行了touchStart,緊接着執行了touchmove,然而手指離開時並不會執行touchEnd事件。那什麼狀況下它纔會執行touchEnd事件呢?
  答案是——把touchmove事件的默認行爲取消的時候。(爲何執行了touchmove就不會執行touchend了呢?
  因此,還要對body的touchmove事件進行處理。思路是在用戶剛開始滑動的時候,判斷用戶是想上下滑動仍是左右滑動,上下滑動的話不作處理,左右滑動的話,對touchmove事件進行preventDefault()操做。如何判斷用戶剛開始滑動時是想左右仍是想上下呢,可經過用戶一開始滑動時X軸和Y軸方向的絕對距離進行判斷。具體代碼以下:
var count = 0; //判斷用戶是否第一次進行touchmove操做
var startX, startY;
var endX, endY;
var distanceX, distanceY;
$('body').bind('touchstart', function(event) {
    count = 0; //每次開始點擊時清零
    startX = event.targetTouches[0].clientX;
    startY = event.targetTouches[0].clientY;
}).bind('touchmove', function(event) {
    if (count === 0) { //若是是第一次滑動
        endX = event.changedTouches[0].clientX;
        endY = event.changedTouches[0].clientY;
        distanceX = Math.abs(startX - endX);
        distanceY = Math.abs(startY - endY);
        if (distanceX > distanceY) { //若是X絕對距離大於Y絕對距離
            event.preventDefault();
        }
    }
    count++; 
}).bind('touchend', function(event) {
    endX = event.changedTouches[0].clientX;
    endY = event.changedTouches[0].clientY;
    distanceX = Math.abs(startX - endX);
    distanceY = Math.abs(startY - endY);
    if (distanceX > distanceY) {
        startX - endX > 0 ? swipeLeft() : swipeRight();
    }
});
   問題完美解決。如今頁面既可上下滑動也可左右滑動。
 
補充以後google時無心間發現一篇文章(http://www.cnblogs.com/zldream1106/p/mobile_scroll_end.html)
裏面有說到swipe的問題
IOS
當"swipe"時,依次產生以下事件:
touchstart -> touchmove * 屢次 -> touchend -> scroll
Android
當"swipe"時,swipe雖然不會觸發touchend事件,可是會在scroll事件以前觸發一次touchcancel事件,即:
touchstart -> touchmove -> touchcancel->scroll*屢次 
Android端的話親測確實如此,touchmove觸發一次,touchcancel觸發一次。IOS端的目前暫時還沒自測過。
因此,剛那個問題在安卓端的話方法二是可行的,只要把touchend改成touchcancel,但爲了兼容起見,仍是用方法三比較穩妥。
但我還沒明白爲何在安卓webview下swipe沒有觸發touchend事件,這個有待研究。
相關文章
相關標籤/搜索