Le problème que je rencontre est que l'événement dragleave
d'un élément est déclenché lors du survol d'un élément enfant de cet élément. De même, dragenter
n'est pas déclenché lors du survol de nouveau de l'élément parent.
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’elle est supposée faire, c’est notifier l’utilisateur en faisant glisser la variable div
en rouge lorsque vous y faites glisser quelque chose. Cela fonctionne, mais si vous glissez dans l'enfant p
, la dragleave
est déclenchée et la div
n'est plus rouge. Revenir à la liste déroulante div
ne le rend également pas rouge. Il est nécessaire de sortir complètement de la liste déroulante div
et de la glisser à nouveau pour la rendre rouge.
Est-il possible d'empêcher le déclenchement de dragleave
lors d'un déplacement dans un élément enfant?
Mise à jour 2017: TL; DR, recherchez CSS pointer-events: none;
comme décrit dans la réponse ci-dessous de @HD.
Vous avez juste besoin de garder un compteur de références, de l’incrémenter quand vous avez un dragenter, de le décrémenter quand vous avez un dragleave. Lorsque le compteur est à 0, supprimez 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');
}
}
});
Remarque: Dans l'événement drop, réinitialisez le compteur à zéro et effacez la classe ajoutée.
Vous pouvez le lancer ici
Est-il possible d'empêcher le glisser-glisser de tirer lorsque vous faites glisser dans un élément enfant?
Oui.
#drop * {pointer-events: none;}
Ce CSS semble être suffisant pour Chrome.
Lorsqu’on l’utilise avec Firefox, le #drop ne devrait pas avoir de nœuds de texte directement (sinon, il existe un problème étrange dans lequel un élément "le laisse à lui-même" ); utilisez un div inside #drop pour tout mettre à l'intérieur)
Voici un jsfiddle résolvant la question originale (cassé) exemple .
J'ai également créé une version simplifiée forkée à partir de l'exemple de @Theodore Brown, mais basée uniquement sur ce CSS.
Cependant, tous les navigateurs n’ont pas implémenté cette CSS: http://caniuse.com/pointer-events
En voyant le code source de Facebook, je pouvais trouver ce pointer-events: none;
à plusieurs reprises, mais il est probablement utilisé conjointement avec des solutions de secours en cas de dégradation. Au moins, c'est si simple et cela résout le problème dans de nombreux environnements.
Ici, la solution multi-navigateur 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 zone de largage, avec la largeur et la hauteur héritées, la position absolue, qui s'affichera au démarrage du glisser-déposer.
Donc, après avoir montré ce masque, vous pouvez résoudre le problème en attachant les autres événements glisser-déplacer et déposer dessus.
Après avoir quitté ou laissé tomber, vous masquez à nouveau le masque.
Simple et sans complications.
(Obs.: Conseil de Greg Pettit - Vous devez vous assurer que le masque plane au-dessus de la boîte, y compris la bordure)
La "bonne" façon de résoudre ce problème consiste à désactiver les événements de pointeur sur les éléments enfants de la cible de dépôt (comme dans la réponse de @ H.D.). Voici un jsFiddle que j'ai créé qui illustre cette technique . Malheureusement, cela ne fonctionne pas dans les versions d'Internet Explorer antérieures à IE11, car elles ne prenaient pas en charge les événements de pointeur .
Heureusement, j'ai réussi à trouver une solution de contournement qui fonctionne dans les anciennes versions d'IE. En gros, il s’agit d’identifier et d’ignorer les événements dragleave
qui surviennent lors d’un glissement sur des éléments enfants. Étant donné que l'événement dragenter
est déclenché sur les nœuds enfants avant l'événement dragleave
sur le parent, des écouteurs d'événement distincts peuvent être ajoutés à chaque nœud enfant, ce qui permet d'ajouter ou de supprimer une classe "ignorer-glisser-laisser" de la bibliothèque. déposer la cible. Ensuite, l'écouteur d'événements dragleave
de la cible de dépôt peut simplement ignorer les appels qui surviennent lorsque cette classe existe. Voici un jsFiddle montrant cette solution de contournement . Il est testé et fonctionne sous Chrome, Firefox et IE8 +.
Mise à jour:
J'ai créé n jsFiddle illustrant une solution combinée à l'aide de la détection de fonctionnalités, où les événements de pointeur sont utilisés s'ils sont pris en charge (actuellement Chrome, Firefox et IE11), et le navigateur revient à ajouter des événements aux nœuds enfants si l'événement de pointeur le support n'est pas disponible (IE8-10).
Cela fait un certain temps que cette question est posée et que de nombreuses solutions (y compris de très mauvais programmes) sont proposées.
J'ai réussi à résoudre le même problème que j'ai eu récemment grâce à la réponse dans ce answer et j'ai pensé que cela pourrait être utile à quelqu'un qui passe par cette page . evenet.target
dans ondrageenter
chaque fois qu'il est appelé sur l'un des éléments parent ou enfant. Puis, dans ondragleave
, vérifiez si la cible actuelle (event.target
) est égale à l'objet que vous avez stocké dans ondragenter
.
Le seul cas où ces deux éléments correspondent est lorsque votre glisser-déposer quitte la fenêtre du navigateur.
La raison pour laquelle cela fonctionne bien est lorsque la souris quitte un élément (par exemple, el1
) et entre un autre élément (par exemple, el2
), le el1.ondragenter
est d'abord appelé, puis el2.ondragleave
. event.target
sera ''
à la fois dans el1.ondragenter
et el2.ondragleave
uniquement lorsque la glissade quitte/entre dans la fenêtre du navigateur.
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 simple page html:
<!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 division interne (# zone de dépôt de fichier) beaucoup plus grande chaque fois qu'un fichier est déplacé vers l'écran de sorte que l'utilisateur puisse facilement déposer les fichiers au bon endroit.
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 pour vérifier si l'élément e.target
est identique à l'élément this
, mais je n'ai pu obtenir aucune amélioration.
La façon dont j'ai résolu ce problème était un peu un bidouillage, 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');
}
}
Une solution très simple consiste à utiliser la propriété CSS pointer-events
. Il suffit de définir sa valeur sur none
lors de dragstart sur chaque élément enfant. Ces éléments ne déclencheront plus d'événements liés à la souris, ils ne la verront donc pas et ne déclenchera donc pas le dragleave sur le parent.
N'oubliez pas de redéfinir cette propriété sur auto
lorsque vous terminez le glissement;)
Vous pouvez le réparer dans Firefox en vous inspirant 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, cela ne fonctionne pas dans Chrome car relatedTarget
ne semble pas exister lors des événements dragleave
et je suppose que vous travaillez dans Chrome car votre exemple n'a pas fonctionné dans Firefox. Voici une version avec le code ci-dessus implémenté.
Et voilà, une solution pour 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 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érons que cela fonctionne, voici un violon .
J'ai écrit une petite bibliothèque appelée Dragster pour gérer ce problème, fonctionne partout sauf en silence, 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 en utilisant les événements personnalisés de jQuery)
Pas sûr que ce navigateur croisé, mais j'ai testé dans Chrome et cela résout mon problème:
Je veux glisser et déposer un fichier sur la page entière, mais mon glisser-glisser est déclenché lorsque je glisse sur l'élément enfant. Ma solution était de regarder le x et le y de la souris:
j'ai un div qui recouvre toute ma page, quand la page se charge je le cache.
lorsque vous faites glisser le document, je le montre et lorsque vous déposez sur le parent, il le gère, et lorsque vous quittez 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 pk7. Cela a fonctionné, mais cela pourrait être fait un peu mieux sans aucun élément supplémentaire.
En gros, l’idée est la même: ajouter une couche supplémentaire invisible sur la surface de dépôt. Permet seulement de le faire sans aucun élément dom supplémentaire. Voici la partie où les pseudo-éléments CSS sont venus jouer.
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);
Cette règle suivante créera une superposition entièrement couverte pour la zone de dépôt.
#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 cela aide quelqu'un avec le même problème.
Une solution simple consiste à ajouter la règle css pointer-events: none
au composant enfant pour empêcher 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 not triggering dragleave</p>
</div>
Je suis tombé sur 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 que ce soit crossbrowser (peut dépendre de l'ordre même du bouillonnement)
J'utiliserai jQuery pour plus de simplicité, mais la solution doit être indépendante du framework.
L'événement crée une bulle parentale dans les deux sens, de la manière suivante:
<div class="parent">Parent <span>Child</span></div>
Nous attachons 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 à peu près tout. :) cela fonctionne car même si onEnter sur l'enfant se déclenche avant onLeave sur le parent, nous le retardons légèrement en inversant l'ordre, de sorte que la classe est supprimée en premier, puis renvoyée au bout d'une seconde.
Il suffit de vérifier si l'élément survolé est un enfant, s'il ne l'est pas, alors ne supprimez 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 le clientRect 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, cette suggestion a fonctionné exactement comme prévu. Je souhaitais fournir un repère uniquement lorsque les fichiers étaient déplacés et que le glissement de document entraînait des scintillements douloureux sur le navigateur Chrome.
C’est ainsi que j’ai résolu le problème, en jetant également des informations appropriées 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 module de glisser-déposer appelé drip-drop qui corrige ce comportement bizarre, entre autres. Si vous recherchez un bon module de glisser-déposer de bas niveau que vous pouvez utiliser comme base pour tout (téléchargement de fichier, glisser-déposer intégré à l'application, glisser de ou vers des sources externes), cochez cette case. module sur:
https://github.com/fresheneesz/drip-drop
Voici comment vous feriez ce que vous essayez de faire en goutte à goutte:
$('#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 celle que j’ai utilisée dans le goutte-à-goutte, mais la réponse la mieux notée manque les étapes importantes qui provoqueront des ruptures 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
}
});
L'événement "dragleave" est déclenché lorsque le pointeur de la souris quitte la zone de glissement du conteneur cible.
Cela a beaucoup de sens car dans de nombreux cas, seul le parent peut être droppable et non les descendants . Je pense que event.stopPropogation () aurait dû gérer ce cas, mais semble ne pas le faire t faire le tour.
Certaines des solutions susmentionnées semblent fonctionner dans la plupart des cas, mais échouent dans le cas d'enfants ne prenant pas en charge les événements dragenter/dragleave, tels que iframe.
Une solution consiste à vérifier le event.relatedTarget et à vérifier s'il réside dans le conteneur, puis à ignorer l'événement dragleave comme je l'ai fait ici:
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");
});
Vous pouvez trouver un violon qui fonctionne ici !
J'ai eu un problème similaire: mon code pour masquer l'événement Droplone sur dragleave pour body a été déclenché de façon concomitante lorsque le survol d'éléments enfant faisait scintiller la zone de largage dans Google Chrome.
J'ai pu résoudre ce problème en programmant la fonction permettant de masquer Dropzone au lieu de l'appeler immédiatement. Ensuite, si un autre glisser-déposer ou dragleave est déclenché, l'appel de fonction planifié 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);
Vous pouvez utiliser une temporisation avec un indicateur transitioning
et écouter sur l'élément du haut. dragenter
/dragleave
à partir d'événements enfants se propagera dans le conteneur.
Puisque dragenter
sur l'élément enfant est déclenché avant dragleave
du conteneur, nous définirons l'indicateur comme étant en transition pendant 1 ms ... l'écouteur dragleave
recherchera l'indicateur avant que le signal 1ms soit activé.
L'indicateur sera vrai uniquement lors des transitions vers les éléments enfants et ne le sera pas lors de la transition vers un élément parent (du conteneur)
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/
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');
}
}
});
Voici une autre approche basée sur le calendrier des événements.
L'événement dragenter
distribué à partir de l'élément enfant peut être capturé par l'élément parent et il se produit toujours avant le dragleave
. Le délai entre ces deux événements est très court, plus court que toute action humaine possible de la souris. L’idée est donc de mémoriser le moment où une dragenter
se produit et de filtrer les événements dragleave
qui se produisent "pas trop rapidement" après ...
Ce court exemple 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
}
})
Vous devez supprimer les événements de pointeur pour tous les objets enfants de la cible glissée.
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) {
//
}
}
}
Essayez simplement d'utiliser event.eventPhase. Il sera défini sur 2 (Event.AT_TARGET) uniquement si la cible est entrée. Sinon, la valeur est 3 (Event.BUBBLING_PHASE).
J'ai utilisé 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 voici 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 .Elle fonctionne bien dans Chrome et Edge.
Cette solution assez simple fonctionne pour moi jusqu'à présent, en supposant que votre événement est attaché à chaque élément glisser individuellement.
if (evt.currentTarget.contains(evt.relatedTarget)) {
return;
}
Solution très simple:
parent.addEventListener('dragleave', function(evt) {
if (!parent.contains(evt.relatedTarget)) {
// Here it is only dragleave on the parent
}
}
pimvdb ..
Pourquoi n'essayez-vous pas d'utiliser drop au lieu de dragleave. Cela a fonctionné pour moi. J'espère que ceci résoudra 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");
}
});