如何同时绑定 Mousedown 和 Touchstart,但不响应两者?安卓、jQuery

IT技术 javascript android jquery
2021-02-22 15:39:08

在一个也可以在移动设备上查看的网站上工作,需要在 touchstart 和 mousedown 上绑定一个动作。

看起来像这样

 $("#roll").bind("mousedown touchstart", function(event){

 someAction();

它在 Iphone 上运行良好,但在 Android 上它响应两次。

event.stopPropagation();
event.preventDefault();

添加此代码为 Android Chrome 修复了它,但不适用于 Android 默认浏览器。任何其他可以解决所有android问题的技巧?

6个回答
element.on('touchstart mousedown', function(e) {
    e.preventDefault();
    someAction();
});

preventDefault根据规范取消活动

你得到了touchstart,但是一旦你取消它你就不再得到mousedown 了与接受的答案所说的相反,stopPropagation除非您需要,否则您不需要打电话即使取消,事件也会正常传播。浏览器会忽略它,但你的钩子仍然可以工作。

Mozilla同意我的观点

在 touchstart 或系列的第一个 touchmove 事件上调用 preventDefault() 可防止触发相应的鼠标事件

编辑:我刚刚再次阅读了这个问题,你说你已经这样做了,但它没有修复 Android 默认浏览器。不确定接受的答案如何帮助,因为它基本上做同样的事情,只是以更复杂的方式和事件传播错误(touchstart 不传播,但 click 传播)

你可能需要 addEventListener('touchstart', FUNCTION, {passive: false});
2021-04-25 15:39:08
在 android 上,我收到“忽略尝试取消带有 cancelable=false 的 touchmove 事件的尝试,例如因为滚动正在进行并且不能被中断”
2021-05-05 15:39:08
这有效,但您甚至无法通过滑动来滚动页面。
2021-05-11 15:39:08

我一直在使用这个功能:

//touch click helper
(function ($) {
    $.fn.tclick = function (onclick) {

        this.bind("touchstart", function (e) { 
            onclick.call(this, e); 
            e.stopPropagation(); 
            e.preventDefault(); 
        });

        this.bind("click", function (e) { 
           onclick.call(this, e);  //substitute mousedown event for exact same result as touchstart         
        });   

        return this;
    };
})(jQuery);

更新:修改答案以同时支持鼠标和触摸事件。

请注意,Windows 8 上的 Chrome 和 Firefox 将在检测到触摸屏时启用触摸事件。因此用户可以在鼠标和触摸输入之间切换。使用此代码鼠标事件将被忽略。
2021-05-11 15:39:08
touchstart相当于mousedown没有click单击需要用户按下按钮。我不明白这如何产生完全相同的结果。
2021-05-12 15:39:08
你会如何解绑这个事件?假设您是否想暂时添加侦听器然后停止触发事件?
2021-05-12 15:39:08
@gregers 你是对是错。Windows 8 确实支持触摸和鼠标事件,但是在触摸时您可以取消“虚拟”鼠标事件以仅处理触摸,并且不会影响真正的鼠标事件,因为它们不会触发触摸事件。
2021-05-15 15:39:08
@daniel.gindi 我的评论是针对此答案的先前修订版:stackoverflow.com/posts/14202543/revisions
2021-05-16 15:39:08

考虑到 gregers 对 win8 和 chrome/firefox 的评论,skyisred 的评论毕竟看起来并不那么愚蠢(:P @ all the haters)尽管我宁愿使用黑名单而不是他建议的白名单,只排除 Android触摸绑定:

var ua = navigator.userAgent.toLowerCase(),
isAndroid = ua.indexOf("android") != -1,
supportsPointer = !!window.navigator.msPointerEnabled,
ev_pointer = function(e) { ... }, // function to handle IE10's pointer events
ev_touch = function(e) { ... }, // function to handle touch events
ev_mouse = function(e) { ... }; // function to handle mouse events

if (supportsPointer) { // IE10 / Pointer Events
    // reset binds
    $("yourSelectorHere").on('MSPointerDown MSPointerMove MSPointerUp', ev_pointer);
} else {
    $("yourSelectorHere").on('touchstart touchmove touchend', ev_touch); // touch events
    if(!isAndroid) { 
        // in androids native browser mouse events are sometimes triggered directly w/o a preceding touchevent (most likely a bug)
        // bug confirmed in android 4.0.3 and 4.1.2
        $("yourSelectorHere").on('mousedown mousemove mouseup mouseleave', ev_mouse); // mouse events
    }
}

顺便说一句:我发现鼠标事件并不总是被触发(如果使用了 stopPropagation 和 preventDefault),特别是我只注意到在 touchend 事件之前直接有一个额外的 mousemove ......真的很奇怪,但上面的代码为我修复了所有(测试了 OSX、Win、iOS 5+6、Android 2+4,每个都使用本机浏览器、Chrome、Firefox、IE、Safari 和 Opera(如果可用)平台。

这太冗长了,你能想象每次 IE 发布新版本时都要维护所有这些吗?
2021-05-13 15:39:08

使用此代码修复

var mobile   = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent); 
var start = mobile ? "touchstart" : "mousedown";
$("#roll").bind(start, function(event){
这也不能正常工作。我已经使用类范围进行了测试,没有使用范围,那么每种方式都有自己的问题。mousedown无论您如何尝试使用touchstart触发函数,将这段代码与类作用域一起使用只会触发mousedown如果没有范围,它会继续触发您第一次触发的结果。
2021-04-26 15:39:08
这是最好的答案,也是唯一有效的答案。约书亚的回答不使用特征检测。您需要检测的唯一功能是 android 当前的怪癖。如果您检测到具有触摸事件的功能,那么它将禁用触摸屏笔记本电脑的鼠标。e.preventDefault() 在 android 上失败。
2021-05-04 15:39:08
-1:使用特征检测(如 Joshua 的回答)而不是 UA 检测。
2021-05-10 15:39:08
具有触摸和鼠标功能的设备呢?
2021-05-19 15:39:08

哇,这个和相关问题中有这么多答案,但没有一个对我有用(Chrome、移动响应、mousedown + touchstart)。但是这个:

(e) => {
  if(typeof(window.ontouchstart) != 'undefined' && e.type == 'mousedown') return;

  // do anything...
}
务实的解决方案:)
2021-05-05 15:39:08