web-dev-qa-db-fra.com

Comment lier Mousedown et Touchstart sans répondre aux deux? Android, JQuery

Travailler sur un site Web qui est également visible sur mobile et qui doit lier une action à la fois au touchstart et au mousedown. 

Ressemble à ça

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

 someAction();

Cela fonctionne bien sur Iphone, mais sur Android, il répond deux fois.

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

L'ajout de ce code a corrigé le problème pour Android Chrome, mais PAS pour le navigateur par défaut Android. D'autres astuces qui peuvent résoudre le problème pour tous les android? 

37
skyisred

J'ai utilisé cette fonction:

//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: Réponse modifiée pour prendre en charge les événements de souris et de contact. 

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

preventDefault annule l'événement, conformément aux spécifications

Vous obtenez touchstart, mais une fois que vous l'annulez, vous n'obtenez plus (mousedown). Contrairement à ce que dit la réponse acceptée, vous n'avez pas besoin d'appeler stopPropagation à moins que vous n'ayez besoin de quelque chose. L'événement se propage normalement même lorsqu'il est annulé. Le navigateur l'ignorera, mais vos crochets continueront à fonctionner.

Mozilla est d'accord avec moi sur celui-ci:

l'appel de preventDefault () sur un touchstart ou le premier événement touchmove d'une série empêche le déclenchement des événements de souris correspondants.

EDIT: Je viens juste de relire la question et vous dites que vous l'avez déjà fait et que cela n'a pas corrigé le navigateur par défaut d'Android. Pas sûr de savoir comment la réponse acceptée a aidé, car elle fait la même chose, d'une manière plus compliquée et avec un bogue de propagation d'événement (touchstart ne se propage pas, mais cliquez si)

22
Radu C

en prenant en compte les commentaires de gregers sur win8 et chrome/firefox, le commentaire de skyisred n’a pas l’air bête après tout (: P @ tous les ennemis). exclure Android de touch-binds:

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: J'ai constaté que les événements de souris ne sont PAS toujours déclenchés (si stopPropagation et preventDefault étaient utilisés), plus précisément, je n'ai remarqué qu'un déplacement de souris supplémentaire directement avant un événement touchend ... un bug vraiment étrange testé OSX, Win, iOS 5 + 6, Android 2 + 4 avec chacun un navigateur natif, Chrome, Firefox, IE, Safari et Opera, le cas échéant).

4
Jörn Berkefeld

Fixé en utilisant ce code

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

Je pense que le meilleur moyen est:

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

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

Cette solution native fonctionnait mieux pour moi:

  1. Ajoutez un événement touchstart aux paramètres du document avec un touch = true global.
  2. Dans le gestionnaire mousedown/touchstart, empêchez tous les événements mousedown lorsqu'un écran tactile est détecté: if (touch && e.type === 'mousedown') return;
0
Raine Revere

Écrivez ce code et ajoutez une requête j de perforation de requête tactile

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);    
} 
0
Mohsin Kureshi

Je vous recommande d'essayer jquery-fast-click . J'ai essayé l'autre approche sur cette question et autres . Chaque problème corrigé et introduit un autre. fast-click a fonctionné pour la première fois sur les navigateurs tactiles Android, iOS, de bureau et de bureau (groan).

0
Adam Rabung