【问题标题】:Android browser: touchcancel being fired althought touchmove has preventDefaultAndroid 浏览器:虽然 touchmove 具有 preventDefault,但仍会触发 touchcancel
【发布时间】:2013-04-03 09:03:33
【问题描述】:

我正在尝试构建一个网页,它可以感知用户的触摸并沿着画布拖动和对象。

所以我正在做这样的事情:

var touchStart = function(e) {
    e.preventDefault();
    // Do stuff
}
var touchMove = function(e) {
    e.preventDefault();
    console.log("Touch move");
    // Move objs
}
var touchEnd = function(e) {
    e.preventDefault();
    console.log("Touch start!");
    // clean up stuff
}
var touchCancel = function(e) {
    e.preventDefault();

    // Oh NO touch cancel!
    console.log("Touch cancel!");

}
bindElemOrig.addEventListener('touchstart', touchStart, false);
bindElemOrig.addEventListener('touchmove', touchStart, false);
bindElemOrig.addEventListener('touchend', touchStart, false);
bindElemOrig.addEventListener('touchcancel', touchStart, false);

在某些时候它工作正常。

问题在于,一旦我加载了太多 obj,在我看来 touchmove 响应时间过长,并且 touchcancel 会被触发。问题是,一旦 touchcancel 被触发,我就不再收到 touchmove 的任何事件,并且我无法再感知到移动。

有人遇到过这个问题吗?我知道 Android 中的错误,您必须调用 preventDefault (touchend event in ios webkit not firing?) 但在这种情况下,由于内存负担,它似乎无法正常工作。

谢谢!

【问题讨论】:

标签: javascript android jquery webkit touch


【解决方案1】:

喜欢这个

var touchMove = function(e) {
    e.preventDefault();
    setTimeout(function(){
        console.log("Touch move");
    // Move objs

    })
}

使用 setTimeout 将你的逻辑包裹在 touchmove 中可以解决这个问题

【讨论】:

    【解决方案2】:

    此问题可能是由于 Chrome/Android 中的错误(功能?)。见this bug report

    此测试演示了行为 (JSFiddle):

    <!DOCTYPE html>
    <html>
      <head>
        <title></title>
        <script>
          var delay = 200;
    
          var haltEvent = function(event) {
            event.preventDefault();
            event.stopPropagation();
          };
    
          var pause = function() {
            var startTime = new Date().getTime();
    
            while (new Date().getTime() < startTime + delay);
          };
    
          window.addEventListener('load', function() {
            var target = document.querySelector('#target');
            var status = document.querySelector('#status');
    
            target.addEventListener('touchstart', function(event) {
              haltEvent(event);
              status.innerHTML = '[touchstart]';
            }, true);
    
            target.addEventListener('touchmove', function(event) {
              pause();
              haltEvent(event);
              status.innerHTML = '[touchmove]';
            }, true);
    
            target.addEventListener('touchend', function(event) {
              status.innerHTML = '[touchend]'; 
            }, true);
    
            target.addEventListener('touchcancel', function(event) {
              status.innerHTML = '[touchcancel]'; 
            }, true);
          });
        </script>
        <style>
          #target {
            background-color: green;
            height: 300px;
          }
    
          #status {
            text-align: center;
          }
        </style>
      </head>
      <body>
        <div id="target"></div>
        <p id="status">[]</p>
      </body>
    </html>
    

    我没有发现随机触发的 touchcancel 事件。相反,只要从 touchmove 事件处理程序返回大约 200 毫秒就会触发它。

    【讨论】:

      【解决方案3】:

      Touchcancel 专门设计用于控制触摸事件并在非常小的触摸和移动操作(接近 20 像素,具体取决于浏览器)后执行常规浏览器操作,例如平移或缩放。

      您唯一的选择是:

      1. 切换到指针事件并使用touch-action CSS 属性as explained here 来 防止pointercancel 触发(推荐,但需要 Android 5+)
      2. touchmove 事件处理程序中添加event.preventDefault(),但这也会禁用任何默认操作,如滚动、平移、缩放等。

      您不能在touchcancel 函数中尝试取消或preventDefault(),因为这样做已经太晚了;浏览器已经停止监听touchmove 事件。这是设计使然,而不是错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多