Javascript:除了使用 event.preventDefault() 之外,还有什么让 Chrome for Android 触发 touchmove 和 touchend 事件侦听器的解决方法吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20412982/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 18:26:13  来源:igfitidea点击:

Javascript: Any workarounds for getting Chrome for Android to fire off touchmove and touchend event listeners other than using event.preventDefault()?

javascriptandroidgoogle-chromeevents

提问by Kyle Weems

When using event listeners with the touchmove and touchend events, I can't get Chrome for Android to acknowledge those events unless I first use event.preventDefault(); earlier in the code. If I'm not wanting to block the default scroll functionality, is there any other workaround I can use to get Chrome for Android to acknowledge these events?

当使用带有 touchmove 和 touchend 事件的事件侦听器时,除非我首先使用 event.preventDefault();否则我无法让 Chrome for Android 确认这些事件;在代码的前面。如果我不想阻止默认滚动功能,是否还有其他解决方法可以让 Chrome for Android 确认这些事件?

Sample code:

示例代码:

$(document).ready(function () {
// Bind touch event listeners.
var elem = $('html').get(0);
elem.addEventListener('touchstart', function (e) { console.info('"touchstart" detected. Coordinates - ' + getCoord(e)); });
elem.addEventListener('touchmove', function (e) { console.info('"touchmove" detected. Coordinates - ' + getCoord(e)); });
elem.addEventListener('touchend', function (e) { console.info('"touchend" detected. Coordinates - ' + getCoord(e)); });

function getCoord(e) {
var touch = false;
if (e.touches.length > 0) {
touch = e.touches[0];
} else {
touch = e.changedTouches[0];
}
if (touch) {
return 'x: ' + touch.pageX + ', y: ' + touch.pageY;
}
}

Example fiddle here: http://jsfiddle.net/jQ2VS/1/

示例小提琴在这里:http: //jsfiddle.net/jQ2VS/1/

回答by Henry Chan

Google Chrome will fire a touchcancelevent about 200 milliseconds after touchstartif it thinks the user is panning/scrolling and you do not call event.preventDefault().

谷歌Chrome浏览器会触发一个touchcancel约后200毫秒时touchstart,如果它认为用户平移/滚动和你不来电event.preventDefault()

Assuming that you want to intercept horizontal touch events and let vertical touch events cause panning/scrolling, a workaround would be:

假设您想拦截水平触摸事件并让垂直触摸事件导致平移/滚动,解决方法是:

  1. On touchstart, store the coordinates in a variable, and set iterationto 0.
  2. For each touchmoveevent, set iterationto iteration+1.
  3. When iterationis equal to 4 (just a "magic number" I found to be reliable on my set-up), calculate the total touch offset deltas for x- and y- axes. EDIT: on mobile devices you'll only receive one touchmove without event.preventDefault()
  4. If x-axis offset > y-axis offset * 3 then fire event.preventDefault(). (This ensures the the gesture is pretty much horizontal)
  1. On touchstart,将坐标存储在一个变量中,并设置iteration为 0。
  2. 对于每个touchmove事件,设置iterationiteration+1。
  3. iteration等于 4(只是我发现在我的设置中可靠的“幻数”)时,计算 x 轴和 y 轴的总触摸偏移增量。编辑:在移动设备上你只会收到一个没有 event.preventDefault() 的 touchmove
  4. 如果 x 轴偏移 > y 轴偏移 * 3,则触发 event.preventDefault()。(这确保手势几乎是水平的)

The down-side for this is that user can only either swipe left/right or scroll up/down.

这样做的缺点是用户只能向左/向右滑动或向上/向下滚动。

回答by Giovanni Di Gregorio

Finally I found the solution (pure js) even in case you might want use it for swipe:

最后我找到了解决方案(纯 js),即使你可能想用它刷卡:

var swipe = function() {

    var touchX, touchY, movX, movY, go;

    function prevent(e){
        e.preventDefault();
    }

    function start(e) {
        go = false;
        document.addEventListener("touchmove", prevent, false);
        touchX = e.touches[0].pageX;
        touchY = e.touches[0].pageY;
    }

    function move(e) {
        movX = e.touches[0].pageX - touchX;
        movY = e.touches[0].pageY - touchY;
        if(!go) {
            (Math.abs(movY) < Math.abs(movX)) ? go = true : stop(e);
        } else {
            /* *************** */
            // cast your spell
            /* *************** */
        }
    }

    function stop(e) {
        document.removeEventListener("touchmove", prevent, false);
    }

    document.addEventListener("touchstart", start, true);
    document.addEventListener("touchmove", move, true);
    document.addEventListener("touchend", stop, true);
    document.addEventListener("touchleave", stop, true);
    document.addEventListener("touchcancel", stop, true);

}

Hope this help.

希望这有帮助。

回答by Kinlan

The simplest answer is that you have to preventDefault on the first touchmove event otherwise they will be cancelled.

最简单的答案是您必须在第一个 touchmove 事件上防止默认,否则它们将被取消。

回答by Kinlan

I found that preventing the touchcancel worked fine.

我发现防止 touchcancel 工作正常。

回答by tnt-rox

The accepted answer is not correct.

接受的答案不正确。

On Android if preventDefault is not set on touchstart the device assumes native scrolling and no more touch events are sent to webview. If preventDefault is set all native scrolling is disabled.

在 Android 上,如果在 touchstart 上未设置 preventDefault,则设备假定本机滚动并且不再向 webview 发送触摸事件。如果设置了 preventDefault ,则禁用所有本机滚动。

There is a shim to provide swipe events with native scrolling here : https://github.com/TNT-RoX/android-swipe-shim

这里有一个 shim 提供带有本机滚动的滑动事件:https: //github.com/TNT-RoX/android-swipe-shim