Annuler l'événement click dans le gestionnaire d'événements mouseup

en écrivant du code drag&drop, j'aimerais annuler les évènements clics dans mon handler mouseup. J'ai pensé que prévenir la défaillance devrait faire l'affaire, mais l'événement de clic est toujours déclenché.

y a-t-il un moyen de le faire?


Cela ne fonctionne pas:

<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
  var a = 1;
  e.preventDefault();
});
$("#test").click (function (e) {
  var a = 2;
});
22
demandé sur Andrew Mao 2011-12-27 14:42:15

14 réponses

j'ai eu le même problème et je n'ai pas trouvé de solution non plus. Mais j'ai trouvé un hack qui semble fonctionner.

puisque le handler onMouseUp ne semble pas être en mesure d'annuler le clic sur un lien avec preventDefault ou stopEvent ou quoi que ce soit, nous avons besoin de faire le lien Annuler lui-même. Ceci peut être fait en écrivant un attribut onclick qui retourne false à l'étiquette a Lorsque la traînée commence, et en l'enlevant lorsque la traînée se termine.

et depuis le les gestionnaires onDragEnd ou onMouseUp sont lancés avant que le clic soit interprété par le navigateur, nous devons vérifier où la traînée se termine et quel lien est cliqué et ainsi de suite. Si elle se termine en dehors du lien traîné (nous avons traîné le lien pour que le curseur ne soit plus sur le lien), nous supprimons le handler onclick dans l'onDragEnd; mais si elle se termine là où le curseur est sur le lien traîné (un clic serait initié), nous laissons le onclick-handler se Supprimer lui-même. Assez compliqué, non?

pas le CODE complet, mais juste pour vous montrer l'idée:

// event handler that runs when the drag is initiated
function onDragStart (args) {
  // get the dragged element
  // do some checking if it's a link etc
  // store it in global var or smth

  // write the onclick handler to link element
  linkElement.writeAttribute('onclick', 'removeClickHandler(this); return false;');
}

// run from the onclick handler in the a-tag when the onMouseUp occurs on the link
function removeClickHandler (element) {
  // remove click handler from self
  element.writeAttribute('onclick', null);
}

// event handler that runs when the drag ends
function onDragEnds (args) {
  // get the target element

  // check that it's not the a-tag which we're dragging,
  // since we want the onclick handler to take care of that case
  if (targetElement !== linkElement) {
    // remove the onclick handler
    linkElement.writeAttribute('onclick', null);
  }
}

j'espère que cela vous donnera une idée de la façon dont cela peut être accompli. Comme je l'ai dit, ce n'est pas une solution complète, juste d'expliquer le concept.

4
répondu Fredrik Boström 2012-01-19 14:18:06

Utiliser l'événement phase de capture

Mettre un élément autour de l'élément que vous souhaitez annuler l'événement click, et ajouter une capture du gestionnaire d'événement.

var btnElm = document.querySelector('button');

btnElm.addEventListener('mouseup', function(e){
    console.log('mouseup');
    
    window.addEventListener(
        'click',
        captureClick,
        true // <-- This registeres this listener for the capture
             //     phase instead of the bubbling phase!
    ); 
});

btnElm.addEventListener('click', function(e){
    console.log('click');
});

function captureClick(e) {
    e.stopPropagation(); // Stop the click from being propagated.
    console.log('click captured');
    window.removeEventListener('click', captureClick, true); // cleanup
}
<button>Test capture click event</button>

JSFiddle Démo

Ce qui se passe:

avant le déclenchement de l'événement click sur le button l'événement click sur l'environnement div est déclenché parce qu'il s'est enregistré pour la phase de capture au lieu de la phase de bouillonnement.

le manipulateur captureClick arrête alors la propagation de son événement click et empêche le manipulateur click sur le bouton d'être appelé. Exactement ce que tu voulais. Il se retire ensuite pour le nettoyage.

Capture vs Bouillonnement:

la phase de capture est appelée de la racine DOM jusqu'aux feuilles tandis que la phase de barbotage est de la feuilles jusqu'à la racine (voir: merveilleuse explication de l'ordre des événements ).

jQuery ajoute toujours des événements à la phase de bouillonnement c'est pourquoi nous devons utiliser pur js ici pour ajouter notre événement de capture spécifiquement à la phase de capture.

gardez à l'esprit, QU'IE a introduit le modèle de capture d'événements du W3C avec IE9 de sorte que cela ne fonctionnera pas avec IE < 9.


avec L'API d'événement courant vous ne pouvez pas ajouter un nouveau gestionnaire d'événement à un élément DOM avant un autre qui a déjà été ajouté. Il n'y a pas de paramètre prioritaire et il n'y a pas de solution sûre pour modifier la liste des écouteurs d'événements .

12
répondu flu 2018-09-07 07:41:50

il y a une solution!

cette approche fonctionne très bien pour moi (au moins en chrome):

sur mousedown je ajouter une classe à l'élément qui est actuellement en train de déménager et sur mouseup je supprimer la classe.

cette classe ne fait que les ensembles pointer-events:none

D'une façon ou d'une autre cela le fait fonctionner et l'événement de clic n'est pas déclenché.

6
répondu FDIM 2018-09-07 07:43:04

Le problème est qu'il y a un élément. Il doit répondre aux clics. Il doit également être déplacé. Toutefois, lorsqu'il est déplacé, il doit pas déclencher cliquez quand il est tombé.

un peu tard, mais peut-être que ça aidera quelqu'un d'autre. Créez une variable globale appelée "noclick" ou quelque chose et définissez-la à false. En faisant glisser l'article, définissez noclick à true. Dans votre gestionnaire de clic, si noclick est true, définissez-le à false et puis preventDefault, return false, stopPropagation, etc. Cela ne fonctionnera pas sur Chrome bien que depuis Chrome a déjà le comportement désiré. Faites en sorte que la fonction drag ne règle noclick à true que si le navigateur N'est pas Chrome.

votre gestionnaire de clics sera toujours viré, mais au moins il a un moyen de savoir qu'il vient de revenir de la traînée et se comporter en conséquence.

4
répondu Kaylakaze 2012-05-20 22:58:26

la meilleure solution pour ma situation était:

el.addEventListener('mousedown', (event) => {
  clickTime = new Date()
})

el.addEventListener('click', (event) => {
  if (new Date() - clickTime < 150) {
    // do something
  }
})

cela donne à l'utilisateur 150ms à libérer, s'ils prennent plus de 150ms c'est considéré comme une pause, plutôt qu'un clic

2
répondu Kim T 2018-06-23 22:20:10

comme ce sont des événements différents, vous ne pouvez pas annuler onclick de onmouseup , si vous appelez preventDefault ou cancelBubble , ou quoi que ce soit, vous empêchez l'événement onmouseup d'être traité plus loin. L'événement onclick est toujours en attente, encore à être tiré, pour ainsi dire.

ce dont vous avez besoin est votre propre drapeau booléen, par exemple isDragging . Vous pouvez définir ceci à true lorsque vous faites glisser des start (par exemple dans onmousedown , ou n'importe quoi d'autre).

mais si vous le réinitialisez à false directement à partir de onmouseup , vous ne traînerez plus lorsque vous recevrez votre onclick événement ( isDragging == false ), parce que onmouseup feux avant onclick fait.

donc ce que vous devez faire est d'utiliser un court délai d'attente (par exemple setTimeout(function() {isDragging = false;}, 50); ), donc quand votre événement onclick est déclenché, isDragging sera toujours true , et votre onclick gestionnaire d'événement peut tout simplement avoir if(isDragging) return false; avant qu'il ne fasse quoi que ce soit autre.

1
répondu Lee Kowalkowski 2012-06-17 20:21:16

c'est peut-être possible, mais je ne suis pas sûr que vous puissiez gérer ce type de gestion evt avec jQuery. cet exemple de code ne doit pas être éloigné de votre attente ou du moins vous donner une direction.

function AddEvent(id, evt_type, ma_fonction, phase) {
    var oElt = document.getElementById(id);
    // modèle W3C mode bubbling
    if( oElt.addEventListener ) {
        oElt.addEventListener(evt_type, ma_fonction, phase);
    // modèle MSIE
    } else if( oElt.attachEvent ) {
        oElt.attachEvent('on'+evt_type, ma_fonction);
    }
    return false;
}

function DelEvent(id, evt_type, ma_fonction, phase) {
    var oElt = document.getElementById(id);
    // modèle W3C mode bubbling
    if( oElt.removeEventListener ) {
        oElt.removeEventListener(evt_type, ma_fonction, phase);
    // modèle MSIE
    } else if( oElt.detachEvent ) {
        oElt.detachEvent('on'+evt_type, ma_fonction);
    }
    return false;
}

    var mon_id = 'test';
    var le_type_evt = "mouseup";
    var flux_evt = false; // prevent bubbling
    var action_du_gestionnaire = function(e) {
        alert('evt mouseup on tag <div>');

        // 1ère méthode : DOM Lev 2
        // W3C
            if ( e.target )
                e.target.removeEventListener(le_type_evt, arguments.callee, flux_evt);
        // MSIE
            else if ( e.srcElement )
                e.srcElement.detachEvent('on'+le_type_evt, arguments.callee);

        // 2ème méthode DOM Lev2
        // DelEvent(mon_id, le_type_evt, action_du_gestionnaire, flux_evt);
    };


    AddEvent(mon_id, le_type_evt, action_du_gestionnaire, flux_evt);
0
répondu hornetbzz 2011-12-30 23:50:31

j'ai récemment fait face au même problème. Voici ma solution:)

    initDrag: function (element) {
        var moved = false,
            target = null;

        function move(e) {
            // your move code
            moved = true;
        };

        function end(e) {
            var e = e || window.event,
                current_target = e.target || e.srcElement;

            document.onmousemove = null;
            document.onmouseup = null;

            // click happens only if mousedown and mouseup has same target
            if (moved && target === current_target) 
                element.onclick = click;

            moved = false;
        };

        function click(e) {
            var e = e || window.event;

            e.preventDefault();
            e.stopPropagation();

            // this event should work only once
            element.onclick = null;
        };

        function init(e) {
            var e = e || window.event;
            target = e.target || e.srcElement;

            e.preventDefault();

            document.onmousemove = move;
            document.onmouseup = end;
        };

        element.onmousedown = init;
    };
0
répondu starl1ng 2012-07-29 13:28:38

c'est ma solution pour glisser et cliquer sur le même élément.

$('selector').on('mousedown',function(){
  setTimeout(function(ele){ele.data('drag',true)},100,$(this));
}).on('mouseup',function(){
  setTimeout(function(ele){ele.data('drag',false)},100,$(this));
}).on('click',function(){
  if($(this).data('drag')){return;}
  // put your code here
});
0
répondu Quyền Lê 2017-06-27 09:48:22

la solution que j'utilise est la suivante:

var disable_click = false;

function click_function(event){
    if (!disable_click){
        // your code
    }
}

function mouse_down_function(event){
    disable_click = false; // will enable the click everytime you click
    // your code
}

function mouse_up_function(event){
    // your code
}

function mouse_drag_function(event){
    disable_click = true; // this will disable the click only when dragging after clicking
   // your code
}

attachez chaque fonction à l'événement approprié selon le nom !

0
répondu Hammi Cloud 2018-04-25 21:27:12

ma solution ne nécessite pas de variables globales ou de timeout ou de changer les éléments html juste jquery qui a sûrement un certain aquivalent dans JS simple.

je déclare une fonction pour onClick

function onMouseClick(event){
     // do sth
}

je déclare une fonction pour MouseDown (u peut aussi faire la même chose dans mouse up) pour décider si gérer un événement onclick ou non

function onMouseDown(event){
     // some code to decide if I want a click to occur after mouseup or not
    if(myDecision){
        $('#domElement').on("click", onMouseClick);
    }
    else $('#domElement').off("click");
} 

note rapide: vous devez vous assurer que

$('#domElement').on("click", onMouseClick); n'est pas exécutée plusieurs fois. Il me semble que dans le cas où il est l'onMouseClick sera appelé plusieurs fois aussi.

0
répondu Tom 2018-09-09 18:19:24
$(document).mouseup(function(event){

    event.preventDefault(); // this prevents only a default action but previously assigned listeners will be called
    event.stopImmediatePropagation() // if there are  others listeners which that shouldn't call 
}
-1
répondu abuduba 2011-12-27 11:30:16
$(document).mouseup(function(event){ // make sure to set the event parameter
    event.preventDefault(); // prevent default, like you said
});

la chose importante à noter est le paramètre event .

EDIT: Vous voulez annuler la drague?

la façon que je sais de faire ceci est d'utiliser soit bind() (pour les versions plus anciennes de jQuery) ou on() (pour jQuery 1.7+) Pour attacher l'événement de mousedown, puis utiliser unbind() ou off() respectivement pour le détacher.

$(document)
    .on("mousedown", function(){...})
    .on("mouseup", function(){
        $(document).off("mousedown");
    });
-1
répondu Purag 2011-12-27 12:49:32

si vous souhaitez supprimer l'événement de clic vous avez Ajouter la déclaration événement.preventDefault () dans le gestionnaire d'événements click seulement et non le gestionnaire d'événements mouseup. Utilisez le code ci-dessous pour le faire fonctionner.

<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
  var a = 1;

});
$("#test").click (function (e) {
 e.preventDefault();
  var a = 2;
});

J'espère que ça résoudra votre problème.

-1
répondu AmGates 2011-12-28 07:47:16