HTML5 dragleave tiré lors de la mise en vol stationnaire d'un élément enfant
le problème que je rencontre est que l'événement dragleave
d'un élément est déclenché lorsque l'élément enfant de cet élément est en vol stationnaire. De plus, dragenter
n'est pas déclenché lorsque l'élément parent est de nouveau en vol stationnaire.
j'ai fait un violon simplifié: 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>
avec le JavaScript suivant:
$('#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");
}
});
Ce qu'il est censé faire est de notifier l'utilisateur en faisant la goutte div
rouge lors du déplacement de quelque chose là. Cela fonctionne, mais si vous traînez dans le p
enfant, le dragleave
est tiré et le div
n'est plus rouge. Le fait de revenir à la chute div
ne le rend pas rouge non plus. Il est nécessaire de se déplacer complètement hors de la chute div
et traîner à nouveau dans elle pour la rendre rouge.
est-il possible d'empêcher dragleave
de tirer en se glissant dans un élément enfant?
2017 mise à Jour: TL;DR, Regarder CSS pointer-events: none;
comme décrit dans la @H. D. la réponse ci-dessous qui fonctionne dans les navigateurs modernes et IE11.
28 réponses
vous avez juste besoin de garder un compteur de référence, incrémenter quand vous obtenez un dragster, décrémenter quand vous obtenez un dragleave. Lorsque le compteur est à 0-supprimer la classe.
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');
}
}
});
Note: dans l'événement de chute, réinitialiser le compteur à zéro, et effacer la classe ajoutée.
vous pouvez l'exécuter ici
est-il possible d'empêcher dragleave de tirer lorsqu'on le traîne dans un élément enfant?
Oui.
#drop * {pointer-events: none;}
que les CSS semblent suffisants pour le Chrome.
tout en l'utilisant avec Firefox, le # drop ne devrait pas avoir de noeuds de texte directement (sinon il y a un étrange problème où un élément " leave it to itself" ), donc je suggère de le laisser avec un seul élément (par exemple, utiliser un div à l'intérieur de #drop de tout mettre à l'intérieur)
Voici un jsfiddle la résolution de la question d'origine (cassé) exemple .
j'ai aussi fait une version simplifiée bifurquée de l'exemple @Theodore Brown, mais basée seulement dans cette CSS.
pas tous les navigateurs ont ce CSS mis en œuvre, bien que: http://caniuse.com/pointer-events
en voyant le code source de Facebook, je pourrais trouver ce pointer-events: none;
plusieurs fois, mais il est probablement utilisé avec des retombées de dégradation gracieuse. Au moins, c'est si simple et résout le problème pour beaucoup d'environnements.
ici, la solution cross-Browser la plus simple (sérieusement):
jsfiddle <-- essayez de faire glisser un fichier à l'intérieur de la boîte
vous pouvez faire quelque chose comme ça:
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);
en quelques mots, vous créez un" masque " à l'intérieur de la dropzone, avec la largeur et la hauteur héritées, la position absolue, qui montrera juste quand le dragover démarre.
Donc, après avoir montré ce masque, vous pouvez faire le trick en attachant les autres événements dragleave & drop dessus.
après avoir quitté ou tomber, vous cachez juste le masque à nouveau.
Simple et sans complications.
(Obs.: Greg Pettit conseils -- Vous devez être sûr que le masque placez l'ensemble de la zone, y compris les frontaliers)
la" bonne " façon de résoudre ce problème est de désactiver les événements pointeurs sur les éléments enfants de la cible de chute (comme dans la réponse de @H. D.). voici un jsFiddle que j'ai créé qui démontre cette technique . Malheureusement, cela ne fonctionne pas dans les versions D'Internet Explorer antérieures à IE11, car ils ne supportaient pas les événements pointeurs .
heureusement, j'ai pu trouver une solution qui fait travail dans les anciennes versions D'IE. Fondamentalement, il s'agit d'identifier et d'ignorer les événements dragleave
qui se produisent en traînant sur les éléments enfants. Étant donné que l'événement dragenter
est lancé sur les noeuds enfants avant l'événement dragleave
sur le parent, des écouteurs d'événements séparés peuvent être ajoutés à chaque noeud enfant qui ajoute ou supprime une classe "ignore-drag-leave" de la cible de chute. Ensuite, l'écouteur d'événements dragleave
de la cible de chute peut tout simplement ignorer les appels qui se produisent lorsque cette classe existe. Voici un jsFiddle la démonstration de cette solution de contournement . Il est testé et fonctionne en Chrome, Firefox et IE8+.
mise à jour:
j'ai créé un jsFiddle démontrant une solution combinée en utilisant la détection de fonctionnalité, où les événements pointeur sont utilisés si pris en charge (actuellement Chrome, Firefox, et IE11), et le navigateur retombe à ajouter des événements aux noeuds enfants si le soutien d'événement pointeur n'est pas disponible (IE8-10).
Cela fait un certain temps que cette question est posée et beaucoup de solutions (y compris des pirouettes laides) sont proposées.
j'ai réussi à corriger le même problème que j'avais récemment grâce à la réponse dans ce réponse et j'ai pensé qu'il peut être utile à quelqu'un qui vient à travers à cette page.
L'idée est de stocker le evenet.target
dans ondrageenter
chaque fois qu'il est appelé sur l'un des parents ou l'enfant élément. Ensuite, dans ondragleave
, vérifiez si la cible courante ( event.target
) est égale à l'objet que vous avez stocké dans ondragenter
.
le seul cas où ces deux cas sont appariés est lorsque votre traînée quitte la fenêtre du navigateur.
la raison pour laquelle cela fonctionne bien est lorsque la souris quitte un élément (dire el1
) et entre dans un autre élément (dire el2
), d'abord le el1.ondragenter
est appelé et puis el2.ondragleave
. Seulement quand la traînée est en sortant/entrant dans la fenêtre du navigateur, event.target
sera ''
dans les deux el1.ondragenter
et el2.ondragleave
.
Voici mon échantillon de travail. Je l'ai testé sur IE9+, Chrome, Firefox et Safari.
(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;
};
})();
et voici une page html simple:
<!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>
avec un style approprié ce que j'ai fait est de rendre la div interne (#file-drop-area) beaucoup plus grand chaque fois qu'un fichier est traîné dans l'écran de sorte que l'utilisateur peut facilement déposer les fichiers à l'endroit approprié.
le problème est que l'événement dragleave
est déclenché lorsque la souris passe devant l'élément enfant.
j'ai essayé diverses méthodes de vérification pour voir si l'élément e.target
est le même que l'élément this
, mais n'a pas pu obtenir d'amélioration.
la façon dont j'ai corrigé ce problème était un peu un piratage, mais fonctionne à 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');
}
}
vous pouvez le fixer dans Firefox avec un peu d'inspiration du code source jQuery :
dragleave: function(e) {
var related = e.relatedTarget,
inside = false;
if (related !== this) {
if (related) {
inside = jQuery.contains(this, related);
}
if (!inside) {
$(this).removeClass('red');
}
}
}
malheureusement, il ne fonctionne pas dans Chrome parce que relatedTarget
semble ne pas exister sur dragleave
événements, et je suppose que vous travaillez dans Chrome parce que votre exemple ne fonctionne pas dans Firefox. Voici une version avec le code ci-dessus implémenté.
une solution très simple est d'utiliser la pointer-events
propriété CSS . Il suffit de mettre sa valeur none
sur dragstart sur chaque élément enfant. Ces éléments ne déclencheront plus d'événements liés à la souris, de sorte qu'ils n'attraperont plus la souris au-dessus d'eux et ne déclencheront donc pas le dragleave sur le parent.
n'oubliez pas de ramener cette propriété à auto
en finissant la traînée ;)
et voilà, une solution pour le Chrome:
.bind('dragleave', function(event) {
var rect = this.getBoundingClientRect();
var getXY = function getCursorPosition(event) {
var x, y;
if (typeof event.clientX === 'undefined') {
// try touch screen
x = event.pageX + document.documentElement.scrollLeft;
y = event.pageY + document.documentElement.scrollTop;
} else {
x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
return { x: x, y : y };
};
var e = getXY(event.originalEvent);
// Check the mouseEvent coordinates are outside of the rectangle
if (e.x > rect.left + rect.width - 1 || e.x < rect.left || e.y > rect.top + rect.height - 1 || e.y < rect.top) {
console.log('Drag is really out of area!');
}
})
Voici une autre solution utilisant le document.elementFromPoint:
dragleave: function(event) {
var event = event.originalEvent || event;
var newElement = document.elementFromPoint(event.pageX, event.pageY);
if (!this.contains(newElement)) {
$(this).removeClass('red');
}
}
Espère que cela fonctionne, voici une violon .
j'ai écrit une petite bibliothèque appelée Dragster pour gérer cette question exacte, fonctionne partout sauf silencieusement ne rien faire dans IE (qui ne prend pas en charge les constructeurs D'événements DOM, mais il serait assez facile d'écrire quelque chose de similaire à l'aide des événements personnalisés de jQuery)
Je ne suis pas sûr que ce navigateur croisé, mais j'ai testé dans Chrome et il résout mon problème:
je veux faire glisser et déposer un fichier sur toute la page, mais mon dragleave est déclenché lorsque je traîne un élément enfant. Ma solution était de regarder le x et le y de la souris:
j'ai une div qui recouvre toute ma page, quand la page se charge je la cache.
quand vous faites glisser le document je le montre, et quand vous tombez sur le parent il le gère, et quand tu quittes le parent, je vérifie x et Y.
$('#draganddrop-wrapper').hide();
$(document).bind('dragenter', function(event) {
$('#draganddrop-wrapper').fadeIn(500);
return false;
});
$("#draganddrop-wrapper").bind('dragover', function(event) {
return false;
}).bind('dragleave', function(event) {
if( window.event.pageX == 0 || window.event.pageY == 0 ) {
$(this).fadeOut(500);
return false;
}
}).bind('drop', function(event) {
handleDrop(event);
$(this).fadeOut(500);
return false;
});
j'avais le même problème et j'ai essayé d'utiliser la solution pk7s. Il a fonctionné, mais il pourrait être fait un peu mieux sans éléments dom supplémentaires.
fondamentalement, l'idée est la même - ajouter une superposition non visible supplémentaire sur la zone droppable. Permet seulement de le faire sans aucun élément supplémentaire dom. Voici la partie où les pseudo-éléments CSS sont venus jouer.
Javascript
var dragOver = function (e) {
e.preventDefault();
this.classList.add('overlay');
};
var dragLeave = function (e) {
this.classList.remove('overlay');
};
var dragDrop = function (e) {
this.classList.remove('overlay');
window.alert('Dropped');
};
var dropArea = document.getElementById('box');
dropArea.addEventListener('dragover', dragOver, false);
dropArea.addEventListener('dragleave', dragLeave, false);
dropArea.addEventListener('drop', dragDrop, false);
CSS
après la règle créera un recouvrement entièrement couvert pour la zone droppable.
#box.overlay:after {
content:'';
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: 1;
}
Voici la solution complète: http://jsfiddle.net/F6GDq/8 /
j'espère que ça aidera n'importe qui avec le même problème.
je suis tombé dans le même problème et voici ma solution - qui je pense est beaucoup plus facile que ci-dessus. Je ne suis pas sûr si c'est crossbrowser (pourrait dépendre de même ordre de bouillonnement)
je vais utiliser jQuery pour la simplicité, mais la solution doit être Cadre indépendant.
l'événement bulles à parent dans l'un ou l'autre sens ainsi donné:
<div class="parent">Parent <span>Child</span></div>
Nous associer des événements
el = $('.parent')
setHover = function(){ el.addClass('hovered') }
onEnter = function(){ setTimeout(setHover, 1) }
onLeave = function(){ el.removeClass('hovered') }
$('.parent').bind('dragenter', onEnter).bind('dragleave', onLeave)
Et c'est tout. :) il fonctionne parce que même si onEnter sur les feux de l'enfant avant de onLeave sur parent, nous le retardons légèrement Inverser l'ordre, donc la classe est enlevée d'abord puis reaplied après une milliseconde.
il suffit de vérifier si l'élément traîné est un enfant, si c'est le cas, alors ne retirez pas votre classe de style "dragover". Assez simple et fonctionne pour moi:
$yourElement.on('dragleave dragend drop', function(e) {
if(!$yourElement.has(e.target).length){
$yourElement.removeClass('is-dragover');
}
})
si vous utilisez HTML5, vous pouvez obtenir la directive client du parent:
let rect = document.getElementById("drag").getBoundingClientRect();
puis dans le parent.dragleave ():
dragleave(e) {
if(e.clientY < rect.top || e.clientY >= rect.bottom || e.clientX < rect.left || e.clientX >= rect.right) {
//real leave
}
}
une solution de travail alternative, un peu plus simple.
//Note: Due to a bug with Chrome the 'dragleave' event is fired when hovering the dropzone, then
// we must check the mouse coordinates to be sure that the event was fired only when
// leaving the window.
//Facts:
// - [Firefox/IE] e.originalEvent.clientX < 0 when the mouse is outside the window
// - [Firefox/IE] e.originalEvent.clientY < 0 when the mouse is outside the window
// - [Chrome/Opera] e.originalEvent.clientX == 0 when the mouse is outside the window
// - [Chrome/Opera] e.originalEvent.clientY == 0 when the mouse is outside the window
// - [Opera(12.14)] e.originalEvent.clientX and e.originalEvent.clientY never get
// zeroed if the mouse leaves the windows too quickly.
if (e.originalEvent.clientX <= 0 || e.originalEvent.clientY <= 0) {
après avoir passé tant d'heures, j'ai eu cette suggestion qui fonctionnait exactement comme prévu. Je voulais fournir une indication seulement quand les fichiers ont été traînés plus de, et document dragover, dragleave causait des clignotements douloureux sur le navigateur Chrome.
C'est comme ça que je l'ai résolu, en jetant aussi des indices appropriés pour l'utilisateur.
$(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
});
j'ai écrit un glisser-déposer le module appelé goutte à goutte qui corrige ce comportement bizarre, entre autres. Si vous êtes à la recherche d'un bon module de drag-and-drop de bas niveau que vous pouvez utiliser comme base pour n'importe quoi (téléchargement de fichier, in-app drag-and-drop, glisser à partir ou vers des sources externes), vous devriez vérifier ce module:
https://github.com/fresheneesz/drip-drop
C'est comme ça que tu ferais vous essayez de faire dans drip-drop:
$('#drop').each(function(node) {
dripDrop.drop(node, {
enter: function() {
$(node).addClass('red')
},
leave: function() {
$(node).removeClass('red')
}
})
})
$('#drag').each(function(node) {
dripDrop.drag(node, {
start: function(setData) {
setData("text", "test") // if you're gonna do text, just do 'text' so its compatible with IE's awful and restrictive API
return "copy"
},
leave: function() {
$(node).removeClass('red')
}
})
})
pour faire cela sans bibliothèque, la technique du compteur est ce que j'ai utilisé dans drip-drop, tho la réponse la mieux cotée manque des étapes importantes qui causeront des choses à casser pour tout sauf la première goutte. Voici comment le faire correctement:
var counter = 0;
$('#drop').bind({
dragenter: function(ev) {
ev.preventDefault()
counter++
if(counter === 1) {
$(this).addClass('red')
}
},
dragleave: function() {
counter--
if (counter === 0) {
$(this).removeClass('red');
}
},
drop: function() {
counter = 0 // reset because a dragleave won't happen in this case
}
});
j'ai eu un problème similaire - mon code pour cacher la dropzone sur l'événement dragleave pour le corps a été tiré de manière contestataire lorsque des éléments enfants en vol stationnaire faisant le flicker dropzone dans Google Chrome.
j'ai pu résoudre cela en programmant la fonction pour cacher dropzone au lieu de l'appeler immédiatement. Ensuite, si un autre draggover ou dragleave est déclenché, l'appel de fonction programmé est annulé.
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);
une solution simple consiste à ajouter la règle css pointer-events: none
au composant enfant pour éviter le déclenchement de ondragleave
. Voir Exemple:
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</p>
</div>
Voici une autre approche basée sur le calendrier des événements.
l'événement dragenter
expédié de l'élément enfant peut être capturé par l'élément parent et il se produit toujours avant le dragleave
. Le timing entre ces deux événements est vraiment court, plus court que n'importe quelle action humaine de la souris. Ainsi, l'idée est de mémoriser le moment où un dragenter
se produit et filtrer dragleave
événements qui se produit "pas trop vite" après ...
cet exemple court fonctionne sur Chrome et Firefox:
var node = document.getElementById('someNodeId'),
on = function(elem, evt, fn) { elem.addEventListener(evt, fn, false) },
time = 0;
on(node, 'dragenter', function(e) {
e.preventDefault();
time = (new Date).getTime();
// Drag start
})
on(node, 'dragleave', function(e) {
e.preventDefault();
if ((new Date).getTime() - time > 5) {
// Drag end
}
})
pimvdb..
pourquoi ne pas essayer d'utiliser drop au lieu de dragleave . Il a travaillé pour moi. espérons que cela résout votre problème.
s'il vous plaît vérifier le jsFiddle: http://jsfiddle.net/HU6Mk/118 /
$('#drop').bind({
dragenter: function() {
$(this).addClass('red');
},
drop: function() {
$(this).removeClass('red');
}
});
$('#drag').bind({
dragstart: function(e) {
e.allowedEffect = "copy";
e.setData("text/plain", "test");
}
});
vous pouvez utiliser un timeout avec un drapeau transitioning
et écouter sur l'élément supérieur. dragenter
/ dragleave
de l'enfant événements va bulle jusqu'au conteneur.
depuis dragenter
sur l'élément enfant feux avant dragleave
du conteneur, nous allons mettre le drapeau montrer comme transition pour 1ms... l'auditeur dragleave
vérifiera le drapeau avant que le 1ms ne soit activé.
le drapeau ne sera vrai que pendant les transitions à l'enfant éléments, et ne sera pas le cas lors de la transition à un élément parent (le contenant)
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 /
Vous devez supprimer les événements de pointeur pour tous les objets enfants de la cible de glisser.
function disableChildPointerEvents(targetObj) {
var cList = parentObj.childNodes
for (i = 0; i < cList.length; ++i) {
try{
cList[i].style.pointerEvents = 'none'
if (cList[i].hasChildNodes()) disableChildPointerEvents(cList[i])
} catch (err) {
//
}
}
}
utilisez ce code 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');
}
}
});
essayez d'utiliser l'événement.eventPhase. Il sera fixé à 2 (Événement.AT_TARGET) uniquement si la cible ist entré, sinon, il est fixé à 3 (Événement.BUBBLING_PHASE).
l'Efe a utilisé l'eventPhase pour lier ou délier l'événement dragleave.
$('.dropzone').on('dragenter', function(e) {
if(e.eventPhase === Event.AT_TARGET) {
$('.dropzone').addClass('drag-over');
$('.dropzone').on('dragleave', function(e) {
$('.dropzone').removeClass('drag-over');
});
}else{
$('.dropzone').off('dragleave');
}
})
Guido
j'ai trouvé une solution similaire mais plus élégante à la réponse de @azlar, et c'est ma solution:
$(document).on({
dragenter: function(e) {
e.stopPropagation();
e.preventDefault();
$("#dragging").show();
},
dragover: function(e) {
e.stopPropagation();
e.preventDefault();
},
dragleave: function(e) {
e.stopPropagation();
e.preventDefault();
if (e.clientX <= 0 ||
// compare clientX with the width of browser viewport
e.clientX >= $(window).width() ||
e.clientY <= 0 ||
e.clientY >= $(window).height())
$("#dragging").hide();
}
});
cette méthode détecte si la souris a quitté la page. Il fonctionne bien dans le Chrome et le bord.