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.

477voto

Woody Punkte 7202

Sie brauchen nur einen Referenzzähler zu führen, den Sie bei einem Dragenter erhöhen und bei einem Dragleave dekrementieren. Wenn der Zähler auf 0 steht - entfernen Sie die Klasse.

var counter = 0;

$('#drop').bind({
    dragenter: function(ev) {
        ev.preventDefault(); // needed for IE
        counter++;
        $(this).addClass('red');
    },

    dragleave: function() {
        counter--;
        if (counter === 0) { 
            $(this).removeClass('red');
        }
    }
});

Hinweis: Setzen Sie den Zähler im Drop-Ereignis auf Null zurück und löschen Sie die hinzugefügte Klasse.

Sie können es ausführen aquí

192voto

H.D. Punkte 3770

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

Ja.

#drop * {pointer-events: none;}

Dieses CSS scheint für Chrome ausreichend zu sein.

Bei der Verwendung mit Firefox sollte das #drop keine direkten Textknoten haben (sonst gibt es eine seltsame Problem, bei dem ein Element "sich selbst überlassen" wird ), daher schlage ich vor, es bei nur einem Element zu belassen (z. B. ein div innerhalb von #drop zu verwenden, um alles darin unterzubringen)

Hier ist ein jsfiddle die Lösung der ursprüngliche Frage (gebrochen) Beispiel .

Ich habe auch eine vereinfachte Version aus dem Beispiel von @Theodore Brown abgeleitet, aber nur in diesem CSS basiert.

Allerdings ist dieses CSS nicht in allen Browsern implementiert: http://caniuse.com/pointer-events

Im Facebook-Quellcode konnte ich Folgendes finden pointer-events: none; mehrmals, wird aber wahrscheinlich zusammen mit Graceful Degradation Fallbacks verwendet. Zumindest ist es so einfach und löst das Problem für eine Vielzahl von Umgebungen.

89voto

Ali Motevallian Punkte 1065

Es ist schon eine ganze Weile her, dass diese Frage gestellt wurde und viele Lösungen (einschließlich hässlicher Hacks) angeboten wurden.

Ich konnte das gleiche Problem, das ich vor kurzem hatte, dank der Antwort in diesem Artikel lösen responder und dachte, es könnte für jemanden, der auf diese Seite kommt, hilfreich sein. Die ganze Idee ist, die evenet.target en ondrageenter jedes Mal, wenn es bei einem der über- oder untergeordneten Elemente aufgerufen wird. Dann in ondragleave prüfen, ob das aktuelle Ziel ( event.target ) ist gleich dem Objekt, das Sie in ondragenter .

Der einzige Fall, in dem diese beiden übereinstimmen, ist, wenn Sie das Browserfenster verlassen.

Der Grund dafür ist, dass dies gut funktioniert, wenn die Maus ein Element verlässt (zum Beispiel el1 ) und gibt ein anderes Element ein (z. B. el2 ), zunächst die el2.ondragenter aufgerufen wird und dann el1.ondragleave . Nur wenn die Ziehfunktion das Browserfenster verlässt/eingeht, event.target wird '' in beiden el2.ondragenter y el1.ondragleave .

Hier ist mein Arbeitsbeispiel. Ich habe es auf IE9+, Chrome, Firefox und Safari getestet.

(function() {
    var bodyEl = document.body;
    var flupDiv = document.getElementById('file-drop-area');

    flupDiv.onclick = function(event){
        console.log('HEy! some one clicked me!');
    };

    var enterTarget = null;

    document.ondragenter = function(event) {
        console.log('on drag enter: ' + event.target.id);
        enterTarget = event.target;
        event.stopPropagation();
        event.preventDefault();
        flupDiv.className = 'flup-drag-on-top';
        return false;
    };

    document.ondragleave = function(event) {
        console.log('on drag leave: currentTarget: ' + event.target.id + ', old target: ' + enterTarget.id);
        //Only if the two target are equal it means the drag has left the window
        if (enterTarget == event.target){
            event.stopPropagation();
            event.preventDefault();
            flupDiv.className = 'flup-no-drag';         
        }
    };
    document.ondrop = function(event) {
        console.log('on drop: ' + event.target.id);
        event.stopPropagation();
        event.preventDefault();
        flupDiv.className = 'flup-no-drag';
        return false;
    };
})();

Und hier ist eine einfache HTML-Seite:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Multiple File Uploader</title>
<link rel="stylesheet" href="my.css" />
</head>
<body id="bodyDiv">
    <div id="cntnr" class="flup-container">
        <div id="file-drop-area" class="flup-no-drag">blah blah</div>
    </div>
    <script src="my.js"></script>
</body>
</html>

Mit richtigen Styling, was ich getan habe, ist, um die innere div (#file-drop-area) viel größer, wenn eine Datei in den Bildschirm gezogen wird, so dass der Benutzer kann leicht fallen die Dateien in den richtigen Ort.

64voto

Kenneth Spencer Punkte 1192

Diese recht einfache Lösung funktioniert bei mir bisher, vorausgesetzt, Ihr Ereignis ist an jedes einzelne Drag-Element angehängt.

if (evt.currentTarget.contains(evt.relatedTarget)) {
  return;
}

63voto

Hier ist die einfachste Cross-Browser-Lösung (ernsthaft):

jsfiddle <-- Versuchen Sie, eine Datei in die Box zu ziehen

So etwas kann man machen:

var dropZone= document.getElementById('box');
var dropMask = document.getElementById('drop-mask');

dropZone.addEventListener('dragover', drag_over, false);
dropMask.addEventListener('dragleave', drag_leave, false);
dropMask.addEventListener('drop', drag_drop, false);

In wenigen Worten: Sie erstellen eine "Maske" innerhalb der Dropzone, mit geerbter Breite und Höhe und absoluter Position, die nur dann angezeigt wird, wenn das Dragover beginnt.
Nachdem Sie diese Maske angezeigt haben, können Sie den Trick anwenden, indem Sie die anderen Drag & Drop-Ereignisse an sie anhängen.

Nach dem Verlassen oder Fallenlassen verstecken Sie die Maske einfach wieder.
Einfach und ohne Komplikationen.

(Obs.: Greg Pettit Beratung - Sie müssen sicher sein, dass die Maske schweben die gesamte Box, einschließlich der Grenze)

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