it-swarm.com.de

Abbrechen des Click-Ereignisses im Mouseup-Ereignishandler

Beim Schreiben von Drag & Drop-Code möchte ich die Klickereignisse in meinem Mouseup-Handler abbrechen. Ich habe mir gedacht, dass das Verhindern der Standardeinstellung den Trick tun sollte, aber das Klickereignis wird immer noch ausgelöst.

Gibt es eine Möglichkeit, dies zu tun?


Das funktioniert nicht:

<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
  var a = 1;
  e.preventDefault();
});
$("#test").click (function (e) {
  var a = 2;
});
23
Yaron

Ich hatte das gleiche Problem und fand auch keine Lösung. Aber ich habe mir einen Hack ausgedacht, der zu funktionieren scheint. 

Da der onMouseUp-Handler anscheinend nicht in der Lage ist, den Klick auf einen Link mit PrevDefault oder StopEvent oder irgendetwas abzubrechen, müssen wir den Link selbst aufheben. Dazu können Sie ein onclick-Attribut schreiben, das zu Beginn des Ziehvorgangs den Wert "a-tag" zurückgibt, und das Ende des Ziehvorgangs wieder entfernen. 

Da die onDragEnd- oder onMouseUp-Handler ausgeführt werden, bevor der Klick vom Browser interpretiert wird, müssen wir überprüfen, wo das Ziehen endet und auf welchen Link geklickt wird. Wenn sie außerhalb des gezogenen Links endet (wir haben den Link so gezogen, dass sich der Cursor nicht mehr auf dem Link befindet), entfernen wir den onclick-Handler in onDragEnd. Wenn es jedoch an der Stelle endet, an der sich der Cursor auf dem gezogenen Link befindet (ein Klick würde ausgelöst), lassen wir den onclick-handler sich entfernen. Kompliziert genug, richtig?

NICHT VOLLSTÄNDIGER CODE, sondern um Ihnen die Idee zu zeigen:

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

Ich hoffe, das gibt Ihnen eine Vorstellung davon, wie dies erreicht werden kann. Wie gesagt, ist dies keine vollständige Lösung, sondern erklärt nur das Konzept. 

4

Verwenden Sie die Ereigniserfassungsphase

Platzieren Sie ein Element um das Element, für das Sie das Klickereignis abbrechen möchten, und fügen Sie ihm einen Erfassungsereignishandler hinzu.

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 Demo

Was geschieht:

Bevor das Klickereignis auf der button ausgelöst wird, wird das Klickereignis auf der umgebenden div ausgelöst, da es sich für die Erfassungsphase anstelle der Blubbernphase registriert hat.

Der captureClick-Handler stoppt dann die Weitergabe seines click-Ereignisses und verhindert, dass der click-Handler für die Schaltfläche aufgerufen wird. Genau das, was du wolltest. Es entfernt sich dann zur Bereinigung.

Capturing vs. Bubbling:

Die Erfassungsphase wird von der DOM-Wurzel bis zu den Blättern aufgerufen, während die Sprudelphase von den Blättern bis zur Wurzel verläuft (siehe: wunderbare Erklärung der Ereignisreihenfolge ).

jQuery fügt der Bubbling-Phase immer Ereignisse hinzu. Deshalb müssen Sie hier reines JS verwenden, um unser Capture-Ereignis speziell für die Capture-Phase hinzuzufügen.

Beachten Sie, dass IE das Ereigniserfassungsmodell des W3C mit IE9 eingeführt hat, sodass dies nicht mit IE <9 funktioniert.


Mit der aktuellen Ereignis-API können Sie einem DOM-Element keinen neuen Ereignishandler hinzufügen, bevor ein anderer bereits hinzugefügt wurde. Es gibt keine Prioritätsparameter und es gibt keine sichere browserübergreifende Lösung, um die Liste der Ereignis-Listener zu ändern .

16
flu

Es gibt eine Lösung!

Dieser Ansatz funktioniert für mich sehr gut (zumindest in Chrom):

ich mousedown füge eine Klasse zu dem Element hinzu, das gerade verschoben wird, und mouseup entferne ich die Klasse.

Alles, was diese Klasse tut, ist pointer-events:none

Irgendwie funktioniert das, und das Klickereignis wird nicht ausgelöst.

7
FDIM

Das Problem ist, dass es ein Element gibt. Es muss auf Klicks reagieren. Es muss auch gezogen werden. Beim Ziehen muss jedoch beim Klicken kein Klick ausgelöst werden.

Ein bisschen spät, aber vielleicht hilft es jemand anderem. Erstellen Sie eine globale Variable mit dem Namen "noclick" oder etwas und setzen Sie sie auf "false". Setzen Sie beim Ziehen des Objekts den Klick auf true. Wenn noclick in Ihrem Click-Handler auf true gesetzt ist, setzen Sie den Wert auf false, und setzen Sie dann Defest, false zurück, stopPropagation usw. Dies funktioniert jedoch nicht in Chrome, da Chrome bereits das gewünschte Verhalten aufweist. Stellen Sie es einfach so ein, dass die Ziehfunktion noclick nur auf true setzt, wenn der Browser nicht Chrome ist.

Ihr Click-Handler wird zwar immer noch ausgelöst, aber er weiß zumindest, dass er gerade vom Ziehen kam und sich entsprechend verhält.

4
Kaylakaze

Die beste Lösung für meine Situation war:

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

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

Dies gibt dem Benutzer 150 ms zur Freigabe, wenn er länger als 150 ms dauert, wird dies als Pause und nicht als Klick betrachtet

2
Kim T

Da es sich um verschiedene Ereignisse handelt, können Sie onclick nicht von onmouseup abbrechen, wenn Sie preventDefault oder cancelBubble oder sonstwie aufrufen, und Sie stoppen die weitere Verarbeitung des onmouseup-Ereignisses. Das onclick-Ereignis steht noch aus, muss aber sozusagen nicht ausgelöst werden.

Was Sie brauchen, ist Ihre eigene boolesche Flagge, z. isDragging. Sie können dies beim Start des Ziehens auf true setzen (z. B. innerhalb von onmousedown oder was auch immer). 

Wenn Sie dies jedoch direkt aus onmouseup auf false zurücksetzen, werden Sie nicht mehr ziehen, wenn Sie Ihr onclick-Ereignis (isDragging == false) erhalten, da onmouseup vor onclick ausgelöst wird.

Was Sie also tun müssen, ist ein kurzes Timeout (z. B. setTimeout(function() {isDragging = false;}, 50);). Wenn Ihr onclick-Ereignis ausgelöst wird, bleibt isDragging weiterhin true und Ihr onclick-Ereignishandler kann if(isDragging) return false; nur verwenden, bevor er irgendetwas anderes tut.

1
Lee Kowalkowski

Möglicherweise ist es möglich, aber ich bin mir nicht sicher, ob Sie diese Art der Verwaltung mit jQuery verwalten können. Dieses Codebeispiel sollte nicht weit von Ihren Erwartungen entfernt sein oder Ihnen zumindest eine Richtung geben.

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
hornetbzz

ich habe kürzlich mit demselben Problem konfrontiert. Hier ist meine Lösung :)

    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
starl1ng

Dies ist meine Lösung zum Ziehen und Klicken auf dasselbe Element.

$('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
Quyền Lê

die Lösung, die ich verwende, ist folgende:

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
}

jede Funktion dem Namen entsprechend an die entsprechende Veranstaltung anhängen!

0

Meine Lösung erfordert keine globalen Variablen oder Zeitüberschreitungen oder das Ändern von HTML-Elementen, sondern nur Jquery, was sicherlich ein gleichwertiges Ergebnis in einfachen js hat.

Ich erkläre eine Funktion für onClick

function onMouseClick(event){
     // do sth
}

Ich erkläre eine Funktion für MouseDown (Sie können dies auch in Mouse Up tun), um zu entscheiden, ob ein Onclick-Ereignis behandelt werden soll oder nicht

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");
} 

Schneller Hinweis: Das sollten Sie sicherstellen
$('#domElement').on("click", onMouseClick); wird nicht mehrmals ausgeführt. Scheint mir, dass der onMouseClick auch mehrfach aufgerufen wird. 

0
Tom