简体   繁体   English

如何同时绑定 Mousedown 和 Touchstart,但不响应两者? Android, JQuery

[英]How to bind both Mousedown and Touchstart, but not respond to both? Android, JQuery

Working on a website that is also viewable on mobile and need to bind an action on both touchstart and mousedown.在一个也可以在移动设备上查看的网站上工作,并且需要在 touchstart 和 mousedown 上绑定一个动作。

Looks like this看起来像这样

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

 someAction();

It works fine on Iphone, but on Android it responds twice.它在 Iphone 上运行良好,但在 Android 上它响应了两次。

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

Adding this code fixed it for Android Chrome, but NOT for Android default browser.添加此代码修复了 Android Chrome,但不适用于 Android 默认浏览器。 Any other tricks that can fix the problem for all android?还有其他技巧可以解决所有 android 的问题吗?

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

preventDefault cancels the event, as per specs 根据规范preventDefault取消事件

You get touchstart , but once you cancel it you no longer get mousedown .你得到了touchstart ,但是一旦你取消它你就不再得到mousedown 了 Contrary to what the accepted answer says, you don't need to call stopPropagation unless it's something you need.与接受的答案所说的相反,除非您需要,否则您不需要调用stopPropagation The event will propagate normally even when cancelled.即使取消,事件也会正常传播。 The browser will ignore it, but your hooks will still work.浏览器会忽略它,但你的钩子仍然可以工作。

Mozilla agrees with me on this one: Mozilla 同意我的观点

calling preventDefault() on a touchstart or the first touchmove event of a series prevents the corresponding mouse events from firing在 touchstart 或系列的第一个 touchmove 事件上调用 preventDefault() 可防止触发相应的鼠标事件

EDIT : I just read the question again and you say that you already did this and it didn't fix the Android default browser.编辑:我刚刚再次阅读了这个问题,你说你已经这样做了,但它没有修复 Android 默认浏览器。 Not sure how the accepted answer helped, as it does the same thing basically, just in a more complicated way and with an event propagation bug (touchstart doesn't propagate, but click does)不确定接受的答案如何帮助,因为它基本上做同样的事情,只是以更复杂的方式和事件传播错误(touchstart 不传播,但 click 传播)

I have been using this function:我一直在使用这个功能:

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

UPDATE: Modified answer to support mouse and touch events together.更新:修改答案以同时支持鼠标和触摸事件。

taking gregers comment on win8 and chrome/firefox into account, skyisred's comment doesn't look that dumb after all (:P @ all the haters) though I would rather go with a blacklist than with a whitelist which he suggested, only excluding Android from touch-binds:考虑到 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
    }
}

BTW: I found that mouse-events are NOT always triggered (if stopPropagation and preventDefault were used), specifically I only noticed an extra mousemove directly before a touchend event... really weird bug but the above code fixed it for me across all (tested OSX, Win, iOS 5+6, Android 2+4 each with native browser, Chrome, Firefox, IE, Safari and Opera, if available) platforms.顺便说一句:我发现鼠标事件并不总是被触发(如果使用了 stopPropagation 和 preventDefault),特别是我只注意到在 touchend 事件之前直接有一个额外的 mousemove ......真的很奇怪,但上面的代码为我修复了所有(测试了 OSX、Win、iOS 5+6、Android 2+4,每个都带有本机浏览器、Chrome、Firefox、IE、Safari 和 Opera(如果可用)平台。

Wow, so many answers in this and the related question, but non of them worked for me (Chrome, mobil responsive, mousedown + touchstart).哇,这个和相关问题中有这么多答案,但没有一个对我有用(Chrome、移动响应、mousedown + touchstart)。 But this:但是这个:

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

  // do anything...
}

This is a very old question but I came across the same problem and found another solution that does not stopPropagation() , preventDefault() or sniff the type of device.这是一个非常古老的问题,但我遇到了同样的问题,并找到了另一个解决方案,该解决方案不会stopPropagation()preventDefault()或嗅探设备类型。 I work on this solution with the assumption that the device supports both touch and mouse inputs.我在假设设备同时支持触摸和鼠标输入的情况下研究此解决方案。

Explanation: When a touch is initiated, the order of events is 1) touchstart 2) touchmove 3) touchend 4) mousemove 5) mousedown 6) mouseup 7) click .解释:当一个触摸被发起时,事件的顺序是 1) touchstart 2) touchmove 3) touchend 4) mousemove 5) mousedown 6) mouseup 7) click Based on this, we will mark a touch interaction from touchstart (first in chain) until click (last in chain).基于此,我们将标记从touchstart (first in chain)到click (last in chain)的触摸交互。 If a mousedown is registered outside of this touch interaction, it is safe to be picked up.如果在此触摸交互之外注册了mousedown ,则可以安全地拾取它。

Below is the logic in Dart, should be very replicable in js.下面是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);
});

As you can see my listeners are placed on document .如您所见,我的听众被放置在document上。 It is thus crucial that I do not stopPropagation() or preventDefault() these events so they can bubble up to other elements.因此,我不stopPropagation()preventDefault()这些事件是至关重要的,这样它们就可以冒泡到其他元素。 This solution helped me single out one interaction to act on and hope it helps you too!这个解决方案帮助我挑选出一种互动来采取行动,希望它也能帮助你!

Fixed using this code使用此代码修复

var mobile   = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent); 
var start = mobile ? "touchstart" : "mousedown";
$("#roll").bind(start, function(event){

I recommend you try jquery-fast-click .我建议您尝试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).快速点击第一次在 Android、ios、桌面和桌面触摸浏览器上工作(呻吟)。

Write this code and add j query punch touch js.it will work simulate mouse events with touch events编写此代码并添加 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);    
} 

This native solution worked best for me:这个本机解决方案最适合我:

  1. Add a touchstart event to the document settings a global touch = true .touchstart事件添加到文档设置 a global touch = true
  2. In the mousedown/touchstart handler, prevent all mousedown events when a touch screen is detected: if (touch && e.type === 'mousedown') return;在 mousedown/touchstart 处理程序中,在检测到触摸屏时阻止所有 mousedown 事件: if (touch && e.type === 'mousedown') return;

I think the best way is :我认为最好的方法是:

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

document.addEventListener( hasTouchStartEvent ? 'touchstart' : 'mousedown', function( e ) {
    console.log( e.touches ? 'TouchEvent' : 'MouseEvent' );
}, false );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM