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.

2voto

visitsb Punkte 511

Nachdem ich so viele Stunden damit verbracht hatte, funktionierte dieser Vorschlag genau wie vorgesehen. Ich wollte nur einen Hinweis geben, wenn Dateien über gezogen wurden, und Dokument Dragover, Dragleave verursachte schmerzhafte Flimmern auf Chrome-Browser.

So habe ich das Problem gelöst, wobei ich auch die richtigen Hinweise für den Benutzer eingebaut habe.

$(document).on('dragstart dragenter dragover', function(event) {    
    // Only file drag-n-drops allowed, http://jsfiddle.net/guYWx/16/
    if ($.inArray('Files', event.originalEvent.dataTransfer.types) > -1) {
        // Needed to allow effectAllowed, dropEffect to take effect
        event.stopPropagation();
        // Needed to allow effectAllowed, dropEffect to take effect
        event.preventDefault();

        $('.dropzone').addClass('dropzone-hilight').show();     // Hilight the drop zone
        dropZoneVisible= true;

        // http://www.html5rocks.com/en/tutorials/dnd/basics/
        // http://api.jquery.com/category/events/event-object/
        event.originalEvent.dataTransfer.effectAllowed= 'none';
        event.originalEvent.dataTransfer.dropEffect= 'none';

         // .dropzone .message
        if($(event.target).hasClass('dropzone') || $(event.target).hasClass('message')) {
            event.originalEvent.dataTransfer.effectAllowed= 'copyMove';
            event.originalEvent.dataTransfer.dropEffect= 'move';
        } 
    }
}).on('drop dragleave dragend', function (event) {  
    dropZoneVisible= false;

    clearTimeout(dropZoneTimer);
    dropZoneTimer= setTimeout( function(){
        if( !dropZoneVisible ) {
            $('.dropzone').hide().removeClass('dropzone-hilight'); 
        }
    }, dropZoneHideDelay); // dropZoneHideDelay= 70, but anything above 50 is better
});

2voto

Lalit Nankani Punkte 33

" dragleave "Dieses Ereignis wird ausgelöst, wenn der Mauszeiger den Ziehbereich des Zielcontainers verlässt.

Dies ist sehr sinnvoll, da in vielen Fällen nur der Elternteil abwerfbar und nicht die Nachkommen. Ich denke event.stopPropogation() hätte diesen Fall behandeln sollen, aber das scheint nicht zu funktionieren.

Die oben erwähnten Lösungen scheinen in den meisten Fällen zu funktionieren, versagen aber bei den Kindern, die keine Unterstützung für schleppen / schleppen lassen Ereignisse, wie zum Beispiel iframe .

1 Umgehung ist die Überprüfung des event.relatedTarget und überprüfen Sie, ob es sich innerhalb des Containers befindet, und ignorieren Sie die dragleave Veranstaltung, wie ich es hier getan habe:

function isAncestor(node, target) {
    if (node === target) return false;
    while(node.parentNode) {
        if (node.parentNode === target)
            return true;
        node=node.parentNode;
    }
    return false;
}

var container = document.getElementById("dropbox");
container.addEventListener("dragenter", function() {
    container.classList.add("dragging");
});

container.addEventListener("dragleave", function(e) {
    if (!isAncestor(e.relatedTarget, container))
        container.classList.remove("dragging");
});

Sie können eine funktionierende Fiedel finden aquí !

1voto

ilovett Punkte 3092

Sie können eine Zeitüberschreitung mit einer transitioning Flagge und hören Sie auf das oberste Element. dragenter / dragleave von Kind-Ereignissen werden in den Container hochgespült.

Depuis dragenter auf dem untergeordneten Element auslöst, bevor dragleave des Containers, setzen wir das Flag show als Übergang für 1ms... die dragleave Listener prüft auf das Flag, bevor die 1ms abgelaufen sind.

Das Flag ist nur bei Übergängen zu untergeordneten Elementen wahr, nicht aber bei Übergängen zu einem übergeordneten Element (des Containers).

var $el = $('#drop-container'),
    transitioning = false;

$el.on('dragenter', function(e) {

  // temporarily set the transitioning flag for 1 ms
  transitioning = true;
  setTimeout(function() {
    transitioning = false;
  }, 1);

  $el.toggleClass('dragging', true);

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

// dragleave fires immediately after dragenter, before 1ms timeout
$el.on('dragleave', function(e) {

  // check for transitioning flag to determine if were transitioning to a child element
  // if not transitioning, we are leaving the container element
  if (transitioning === false) {
    $el.toggleClass('dragging', false);
  }

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

// to allow drop event listener to work
$el.on('dragover', function(e) {
  e.preventDefault();
  e.stopPropagation();
});

$el.on('drop', function(e) {
  alert("drop!");
});

jsfiddle: http://jsfiddle.net/ilovett/U7mJj/

1voto

Mohammad Rezaei Punkte 241

Diesen Code verwenden http://jsfiddle.net/HU6Mk/258/ :

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

         dragleave: function(event) {
             var x = event.clientX, y = event.clientY,
                 elementMouseIsOver = document.elementFromPoint(x, y);
             if(!$(elementMouseIsOver).closest('.red').length) {
                 $(this).removeClass('red');
             }
        }
    });

1voto

Arseny Punkte 5019

Ich hatte ein ähnliches Problem - mein Code zum Ausblenden der Dropzone beim Dragleave-Ereignis für body wurde ständig ausgelöst, wenn ich mit dem Mauszeiger über untergeordnete Elemente fuhr, wodurch die Dropzone in Google Chrome flackerte.

Ich konnte dieses Problem lösen, indem ich die Funktion zum Ausblenden der Dropzone geplant habe, anstatt sie sofort aufzurufen. Wenn dann ein weiteres Dragover oder Dragleave ausgelöst wird, wird der geplante Funktionsaufruf abgebrochen.

body.addEventListener('dragover', function() {
    clearTimeout(body_dragleave_timeout);
    show_dropzone();
}, false);

body.addEventListener('dragleave', function() {
    clearTimeout(body_dragleave_timeout);
    body_dragleave_timeout = setTimeout(show_upload_form, 100);
}, false);

dropzone.addEventListener('dragover', function(event) {
    event.preventDefault();
    dropzone.addClass("hover");
}, false);

dropzone.addEventListener('dragleave', function(event) {
    dropzone.removeClass("hover");
}, false);

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