安卓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事件,这个有待研究。
相关文章
相关标签/搜索