52

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

看起来像这样

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

 someAction();

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

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

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

4

10 回答 10

34
element.on('touchstart mousedown', function(e) {
    e.preventDefault();
    someAction();
});

preventDefault根据规范取消事件

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

Mozilla在这一点上同意我的看法:

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

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

于 2015-07-03T16:02:05.610 回答
32

我一直在使用这个功能:

//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);

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

于 2013-01-07T19:17:04.370 回答
3

考虑到 gregers 对 win8 和 chrome/firefox 的评论,skyisred 的评论毕竟看起来并不那么愚蠢(:P @ 所有的仇恨者)虽然我宁愿使用黑名单而不是他建议的白名单,只排除 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,如果可用)平台。

于 2013-04-11T15:53:22.953 回答
1

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

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

  // do anything...
}
于 2019-03-14T15:10:05.683 回答
0

I recommend you try jquery-fast-click. I tried the other approach on this question and others. Each fixed one issue, and introduced another. fast-click worked the first time on Android, ios, desktop, and desktop touch browsers (groan).

于 2013-09-05T20:20:23.940 回答
0

修复了使用此代码

var mobile   = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent); 
var start = mobile ? "touchstart" : "mousedown";
$("#roll").bind(start, function(event){
于 2012-12-01T21:46:39.873 回答
0

编写此代码并添加 j 查询打孔触摸 js。它将使用触摸事件模拟鼠标事件

function touchHandler(event)
{
    var touches = event.changedTouches,
        first = touches[0],
        type = "";
         switch(event.type)
    {
        case "touchstart": type = "mousedown"; break;
        case "touchmove":  type="mousemove"; break;        
        case "touchend":   type="mouseup"; break;
        default: return;
    }

    var simulatedEvent = document.createEvent("MouseEvent");
    simulatedEvent.initMouseEvent(type, true, true, window, 1, 
                              first.screenX, first.screenY, 
                              first.clientX, first.clientY, false, 
                              false, false, false, 0/*left*/, null);
    first.target.dispatchEvent(simulatedEvent);
    event.preventDefault();
}

function init() 
{
    document.addEventListener("touchstart", touchHandler, true);
    document.addEventListener("touchmove", touchHandler, true);
    document.addEventListener("touchend", touchHandler, true);
    document.addEventListener("touchcancel", touchHandler, true);    
} 
于 2015-10-06T09:23:02.873 回答
0

这是一个非常古老的问题,但我遇到了同样的问题并找到了另一个解决方案,它没有stopPropagation()preventDefault()或者嗅探设备的类型。我在这个解决方案上工作,假设设备支持触摸和鼠标输入。

解释:当触摸开始时,事件的顺序是 1) touchstart2) touchmove3) touchend4) mousemove5) mousedown6) mouseup7) click。基于此,我们将标记从touchstart(链中第一个)到click(链中最后一个)的触摸交互。如果 amousedown在此触摸交互之外注册,则可以安全地拾取它。

下面是 Dart 中的逻辑,在 js 中应该是非常可复制的。

var touchStarted = false;
document.onMouseDown.listen((evt) {
  if (!touchStarted) processInput(evt);
});
document.onClick.listen((evt) {
  touchStarted = false;
});
document.onTouchStart.listen((evt) {
  touchStarted = true;
  processInput(evt);
});

如您所见,我的听众被放置在document. 因此,重要的是我不要stopPropagation()preventDefault()这些事件,这样它们才能冒泡到其他元素。这个解决方案帮助我挑选出一个交互来采取行动,希望它也能帮助你!

于 2022-02-16T01:21:05.453 回答
0

这个原生解决方案最适合我:

  1. 将事件添加touchstart到文档设置一个全局touch = true.
  2. 在 mousedown/touchstart 处理程序中,当检测到触摸屏时阻止所有 mousedown 事件:if (touch && e.type === 'mousedown') return;
于 2018-04-14T20:49:51.413 回答
-1

我认为最好的方法是:

var hasTouchStartEvent = 'ontouchstart' in document.createElement( 'div' );

document.addEventListener( hasTouchStartEvent ? 'touchstart' : 'mousedown', function( e ) {
    console.log( e.touches ? 'TouchEvent' : 'MouseEvent' );
}, false );
于 2016-01-21T07:25:24.637 回答