457 Stimmen

HTML5-Dragleave wird beim Verweilen auf einem untergeordneten Element ausgelöst

Das Problem, das ich habe, ist, dass die dragleave Ereignis eines Elements wird ausgelöst, wenn der Mauszeiger über ein untergeordnetes Element dieses Elements bewegt wird. Auch, dragenter wird nicht ausgelöst, wenn der Mauszeiger wieder zum übergeordneten Element zurückkehrt.

Ich habe eine vereinfachte Fiedel gemacht: http://jsfiddle.net/pimvdb/HU6Mk/1/ .

HTML:

<div id="drag" draggable="true">drag me</div>

<hr>

<div id="drop">
    drop here
    <p>child</p>
    parent
</div>

mit dem folgenden JavaScript:

$('#drop').bind({
                 dragenter: function() {
                     $(this).addClass('red');
                 },

                 dragleave: function() {
                     $(this).removeClass('red');
                 }
                });

$('#drag').bind({
                 dragstart: function(e) {
                     e.allowedEffect = "copy";
                     e.setData("text/plain", "test");
                 }
                });

Es soll den Benutzer benachrichtigen, indem es die Drop div rot, wenn etwas dorthin gezogen wird. Das funktioniert, aber wenn Sie etwas in den Bereich p Kind, das dragleave wird ausgelöst und die div ist nicht mehr rot. Zurück zum Tropfen div macht es auch nicht wieder rot. Es ist notwendig, sich vollständig aus dem Tropfen herauszubewegen div und ziehen Sie es erneut hinein, um es rot zu machen.

Ist es möglich zu verhindern dragleave beim Ziehen in ein untergeordnetes Element nicht ausgelöst wird?

2017 Update: TL;DR, CSS nachschlagen pointer-events: none; wie in der Antwort von @H.D. unten beschrieben, die in modernen Browsern und IE11 funktioniert.

38voto

Theodore Brown Punkte 860

Der "richtige" Weg, dieses Problem zu lösen, besteht darin, Zeigerereignisse auf untergeordneten Elementen des Ablageziels zu deaktivieren (wie in der Antwort von @H.D.). Hier ist ein von mir erstelltes jsFiddle, das diese Technik demonstriert . Leider funktioniert dies nicht in Versionen von Internet Explorer vor IE11, da diese unterstützte keine Zeigerereignisse .

Glücklicherweise konnte ich eine Lösung finden, die tut in alten Versionen des IE funktionieren. Im Wesentlichen geht es um das Erkennen und Ignorieren dragleave Ereignisse, die beim Ziehen über untergeordnete Elemente auftreten. Da die dragenter Ereignis wird auf untergeordneten Knoten ausgelöst, bevor die dragleave Ereignis des übergeordneten Knotens können zu jedem untergeordneten Knoten separate Ereignis-Listener hinzugefügt werden, die eine "ignore-drag-leave"-Klasse zum Ablegeziel hinzufügen oder entfernen. Dann wird das Ablegeziel der dragleave Ereignis-Listener kann Aufrufe, die erfolgen, wenn diese Klasse existiert, einfach ignorieren. Hier ist ein jsFiddle demonstriert diesen Workaround . Es ist getestet und funktioniert in Chrome, Firefox und IE8+.

Aktualisierung:

Ich habe ein jsFiddle zur Demonstration einer kombinierten Lösung mithilfe der Feature-Erkennung, bei der Zeigerereignisse verwendet werden, wenn sie unterstützt werden (derzeit Chrome, Firefox und IE11), und der Browser auf das Hinzufügen von Ereignissen zu untergeordneten Knoten zurückgreift, wenn keine Unterstützung für Zeigerereignisse verfügbar ist (IE8-10).

26voto

azlar Punkte 404

Wenn Sie HTML5 verwenden, können Sie das ClientRect des Elternteils abrufen:

let rect = document.getElementById("drag").getBoundingClientRect();

Dann im parent.dragleave():

dragleave(e) {
    if(e.clientY < rect.top || e.clientY >= rect.bottom || e.clientX < rect.left || e.clientX >= rect.right) {
        //real leave
    }
}

hier ist ein jsfiddle

19voto

FruityFred Punkte 211

Eine sehr einfache Lösung ist die Verwendung der pointer-events CSS-Eigenschaft . Setzen Sie den Wert einfach auf none auf Schleppstart für jedes untergeordnete Element. Diese Elemente lösen keine mausbezogenen Ereignisse mehr aus, so dass sie nicht mehr mit der Maus überfahren werden und somit auch nicht mehr die dragleave auf das Elternteil.

Vergessen Sie nicht, diese Eigenschaft zurückzusetzen auf auto beim Beenden der Schlepperei ;)

19voto

Alexandre Annic Punkte 8495

Eine einfache Lösung ist das Hinzufügen der css-Regel pointer-events: none an die untergeordnete Komponente, um die Auslösung von ondragleave . Siehe Beispiel:

function enter(event) {
  document.querySelector('div').style.border = '1px dashed blue';
}

function leave(event) {
  document.querySelector('div').style.border = '';
}

div {
  border: 1px dashed silver;
  padding: 16px;
  margin: 8px;
}

article {
  border: 1px solid silver;
  padding: 8px;
  margin: 8px;
}

p {
  pointer-events: none;
  background: whitesmoke;
}

<article draggable="true">drag me</article>

<div ondragenter="enter(event)" ondragleave="leave(event)">
  drop here
  <p>child not triggering dragleave</p>
</div>

16voto

Greg Punkte 20050

Das Problem ist, dass die dragleave Ereignis wird ausgelöst, wenn sich die Maus vor dem untergeordneten Element befindet.

Ich habe verschiedene Methoden ausprobiert, um zu prüfen, ob die e.target Element ist dasselbe wie das this Element, konnte aber keine Verbesserung erzielen.

Die Art und Weise, wie ich dieses Problem behoben habe, war ein bisschen hakelig, aber es funktioniert zu 100 %.

dragleave: function(e) {
               // Get the location on screen of the element.
               var rect = this.getBoundingClientRect();

               // Check the mouseEvent coordinates are outside of the rectangle
               if(e.x > rect.left + rect.width || e.x < rect.left
               || e.y > rect.top + rect.height || e.y < rect.top) {
                   $(this).removeClass('red');
               }
           }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X