Le problème que j'ai est que l' dragleave
événement d'un élément est déclenché lors du survol d'un élément enfant de cet élément. En outre, dragenter
n'est pas déclenché lors du survol 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'il est censé faire, c'est d'avertir l'utilisateur en rendant le drop div
rouge quand il y fait glisser quelque chose. Cela fonctionne, mais si vous glissez dans l' p
enfant, le dragleave
est tiré et div
n'est plus rouge. Revenir à la goutte div
ne la rend pas non plus rouge. Il est nécessaire de sortir complètement de la goutte div
et de la faire glisser à nouveau pour la rendre rouge.
Est-il possible d'empêcher le dragleave
tir lors du glissement dans un élément enfant?
Mise à jour 2017: TL; DR, recherchez CSS pointer-events: none;
comme décrit dans la réponse de @ HD ci-dessous qui fonctionne dans les navigateurs modernes et IE11.
dragleave
est toujours déclenché dans ce cas.Réponses:
Il vous suffit de conserver un compteur de référence, de l'incrémenter lorsque vous obtenez un dragenter, de décrémenter lorsque vous obtenez un dragleave. Lorsque le compteur est à 0 - supprimez la classe.
Remarque: Dans l'événement drop, remettez le compteur à zéro et effacez la classe ajoutée.
Vous pouvez l'exécuter ici
la source
pointer-events: none
les enfants. Lorsque je commence à faire glisser, j'ajoute une classe qui a cette propriété, lorsque le glisser est terminé, je supprime la classe. A bien fonctionné sur Safari et Chrome, mais pas sur Firefox.dragenter
j'enregistreevent.currentTarget
dans une nouvelle variabledragEnterTarget
. Tant qu'ildragEnterTarget
est défini, j'ignore les autresdragenter
événements, car ils proviennent d'enfants. Dans tous lesdragleave
cas, je vérifiedragEnterTarget === event.target
. Si c'est faux, l'événement sera ignoré car il a été déclenché par un enfant. Si cela est vrai, je reviensdragEnterTarget
àundefined
.Oui.
Ce CSS semble être suffisant pour Chrome.
En l'utilisant avec Firefox, le #drop ne devrait pas avoir de nœuds de texte directement (sinon il y a un problème étrange où un élément "le laisse à lui-même" ), donc je suggère de le laisser avec un seul élément (par exemple, utilisez un div à l'intérieur # goutte pour tout mettre à l'intérieur)
Voici un jsfiddle résolvant l'exemple de question d'origine (cassé) .
J'ai aussi fait une version simplifiée issue de l'exemple de @Theodore Brown, mais basée uniquement sur ce CSS.
Cependant, tous les navigateurs n'ont pas ce CSS implémenté: http://caniuse.com/pointer-events
En voyant le code source de Facebook, j'ai pu le trouver
pointer-events: none;
plusieurs fois, mais il est probablement utilisé avec des retombées de dégradation gracieuses. Au moins, c'est si simple et résout le problème pour de nombreux environnements.la source
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:
En quelques mots, vous créez un "masque" à l'intérieur de la zone de dépôt, avec une largeur et une hauteur héritées, une position absolue, qui s'affichera au début du glisser.
Ainsi, après avoir montré ce masque, vous pouvez faire l'affaire en y attachant les autres événements glisser-déposer.
Après avoir quitté ou abandonné, il vous suffit de masquer à nouveau le masque.
Simple et sans complications.
(Obs .: conseil de Greg Pettit - Vous devez être sûr que le masque plane sur toute la boîte, y compris la bordure)
la source
Cela fait un certain temps que cette question est posée et de nombreuses solutions (y compris des hacks laids) sont fournies.
J'ai réussi à résoudre le même problème que j'avais récemment grâce à la réponse dans cette réponse et j'ai pensé qu'il pourrait être utile à quelqu'un qui accède à cette page. L'idée est de stocker le
evenet.target
àondrageenter
chaque fois qu'il est appelé sur l'un des éléments parents ou enfants. Ensuite,ondragleave
vérifiez si la cible actuelle (event.target
) est égale à l'objet dans lequel vous avez stockéondragenter
.Le seul cas où ces deux sont identiques est lorsque votre glisser 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 dans un autre élément (par exempleel2
), d'abord leel2.ondragenter
est appelé, puisel1.ondragleave
. Ce n'est que lorsque le glisser quitte / entre dans la fenêtre du navigateur,event.target
sera''
dans les deuxel2.ondragenter
etel1.ondragleave
.Voici mon échantillon de travail. Je l'ai testé sur IE9 +, Chrome, Firefox et Safari.
Et voici une simple page html:
Avec un style correct, ce que j'ai fait est d'agrandir la div intérieure (# file-drop-area) chaque fois qu'un fichier est glissé dans l'écran afin que l'utilisateur puisse facilement déposer les fichiers au bon endroit.
la source
==
sur===
. Vous comparez les références d'objet cible d'événement, cela===
fonctionne donc très bien également.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 @ HD). 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, je suis en mesure de trouver une solution qui fait le travail dans les anciennes versions de IE. Fondamentalement, cela implique d'identifier et d'ignorer les
dragleave
événements qui se produisent lors du glissement sur des éléments enfants. Étant donné que l'dragenter
événement est déclenché sur les nœuds enfants avant l'dragleave
événement sur le parent, des écouteurs d'événement distincts peuvent être ajoutés à chaque nœud enfant qui ajoutent ou suppriment une classe "ignore-drag-Leave" de la cible de dépôt. Ensuite, l'dragleave
écouteur d'événements de la cible cible peut simplement ignorer les appels qui se produisent lorsque cette classe existe. Voici un jsFiddle démontrant cette solution de contournement . Il est testé et fonctionne dans Chrome, Firefox et IE8 +.Mettre à jour:
J'ai créé un jsFiddle montrant une solution combinée utilisant 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 la prise en charge des événements de pointeur n'est pas disponible (IE8 -dix).
la source
dragleave
événement de se déclencher dans Chrome, Firefox et IE11 +. J'ai également mis à jour mon autre solution de contournement pour prendre en charge IE8 et IE9, en plus d'IE10. Il est intentionnel que l'effet dropzone ne soit ajouté qu'en faisant glisser le lien "Faites-moi glisser". D'autres peuvent se sentir libres de modifier ce comportement au besoin pour prendre en charge leurs cas d'utilisation.Le problème est que l'
dragleave
événement est déclenché lorsque la souris passe devant l'élément enfant.J'ai essayé différentes méthodes pour vérifier si l'
e.target
élément est le même que l'this
élément, mais je n'ai pu obtenir aucune amélioration.La façon dont j'ai résolu ce problème était un peu un hack, mais fonctionne à 100%.
la source
if (e.x >= (rect.left + rect.width) || e.x <= rect.left || e.y >= (rect.top + rect.height) || e.y <= rect.top)
e.x
ete.y
.si vous utilisez HTML5, vous pouvez obtenir le clientRect du parent:
Puis dans le parent.dragleave ():
voici un jsfiddle
la source
border-radius
, déplacer le pointeur près du coin laisserait en fait l'élément, mais ce code penserait toujours que nous sommes à l'intérieur (nous avons laissé l'élément mais nous sommes toujours dans le rectangle englobant). Ensuite, ledragleave
gestionnaire d'événements ne sera pas appelé du tout.Une solution très simple consiste à utiliser la
pointer-events
propriété CSS . Définissez simplement sa valeurnone
sur dragstart sur chaque élément enfant. Ces éléments ne déclencheront plus d'événements liés à la souris, ils n'attraperont donc pas la souris dessus et ne déclencheront donc pas le glisser - déposer sur le parent.N'oubliez pas de redéfinir cette propriété à la
auto
fin du glissement;)la source
Cette solution assez simple fonctionne pour moi jusqu'à présent, en supposant que votre événement est attaché à chaque élément de glissement individuellement.
la source
Solution très simple:
la source
Vous pouvez le corriger dans Firefox avec un peu d'inspiration du code source jQuery :
Malheureusement, cela ne fonctionne pas dans Chrome car il
relatedTarget
semble ne pas exister sur lesdragleave
événements, et je suppose que vous travaillez dans Chrome parce que votre exemple ne fonctionnait pas dans Firefox. Voici une version avec le code ci-dessus implémenté.la source
Et voilà, une solution pour Chrome:
la source
border-radius
comme je l'ai expliqué dans mon commentaire sur la réponse de @ azlar ci-dessus.Voici une autre solution utilisant document.elementFromPoint:
J'espère que cela fonctionne, voici un violon .
la source
event.clientX, event.clientY
place, car ils sont relatifs à la fenêtre et non à la page. J'espère que cela aide une autre âme perdue là-bas.Une solution simple consiste à ajouter la règle css
pointer-events: none
au composant enfant pour empêcher le déclenchement deondragleave
. Voir l'exemple:la source
dragged = event.target;clone = dragged.cloneNode();clone.style.pointerEvents = 'none';
Je ne sais pas si ce navigateur croisé, mais j'ai testé dans Chrome et cela 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 fais glisser sur l'élément enfant. Ma solution était de regarder les x et y de la souris:
j'ai un div qui recouvre toute ma page, lorsque la page se charge je la 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.
la source
J'ai écrit une petite bibliothèque appelée Dragster pour gérer ce problème exact, fonctionne partout sauf ne rien faire 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)
la source
J'avais le même problème et j'ai essayé d'utiliser la solution pk7s. Cela a fonctionné mais cela pourrait être fait un peu mieux sans aucun élément dom supplémentaire.
Fondamentalement, l'idée est la même: ajoutez une superposition invisible supplémentaire sur la zone largable. Permet uniquement de le faire sans aucun élément dom supplémentaire. Voici la partie où les pseudo-éléments CSS sont venus jouer.
Javascript
CSS
Cette règle après créera une superposition entièrement couverte pour la zone largable.
Voici la solution complète: http://jsfiddle.net/F6GDq/8/
J'espère que cela aide toute personne ayant le même problème.
la source
Vérifiez simplement si l'élément glissé est un enfant, s'il l'est, puis ne supprimez pas votre classe de style «glisser». Assez simple et fonctionne pour moi:
la source
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 un croisement (cela pourrait dépendre de l'ordre de propagation même)
Je vais utiliser jQuery pour plus de simplicité, mais la solution doit être indépendante du framework.
L'événement bouillonne pour être parent dans les deux sens, étant donné:
Nous attachons des événements
Et c'est tout. :) cela fonctionne parce que même si onEnter sur les incendies d'enfant avant onLeave sur le parent, nous le retardons légèrement en inversant l'ordre, donc la classe est supprimée d'abord puis réappliquée après une milliseconde.
la source
J'ai écrit un module de glisser-déposer appelé goutte-à-goutte qui corrige ce comportement bizarre, entre autres. Si vous cherchez un bon module de glisser-déposer de bas niveau que vous pouvez utiliser comme base pour tout (téléchargement de fichiers, glisser-déposer dans l'application, glisser depuis ou vers des sources externes), vous devriez le vérifier module out:
https://github.com/fresheneesz/drip-drop
Voici comment vous feriez ce que vous essayez de faire en goutte à goutte:
Pour ce faire, sans bibliothèque, la technique du compteur est ce que j'ai utilisé dans le goutte-à-goutte, la réponse la mieux notée manque des étapes importantes qui entraîneront des ruptures pour tout sauf la première goutte. Voici comment procéder correctement:
la source
Une solution de travail alternative, un peu plus simple.
la source
clientX
au-dessus de 0 lorsque la souris est en dehors de la boîte. Certes, mes éléments sontposition:absolute
Après avoir passé tant d'heures, cette suggestion a fonctionné exactement comme prévu. Je voulais fournir un signal uniquement lorsque les fichiers étaient glissés et que le glisser-déplacer du document entraînait des scintillements douloureux sur le navigateur Chrome.
C'est ainsi que je l'ai résolu, en insérant également des indices appropriés pour l'utilisateur.
la source
J'ai eu un problème similaire: mon code pour masquer la zone de dépôt lors de l'événement dragleave pour le corps a été déclenché de manière contagieuse lorsque vous survoliez des éléments enfants, ce qui faisait scintiller la zone de dépôt dans Google Chrome.
J'ai pu résoudre ce problème en planifiant la fonction de masquage de la zone de dépôt au lieu de l'appeler immédiatement. Ensuite, si un autre glisser-déplacer ou glisser-déplacer est déclenché, l'appel de fonction planifié est annulé.
la source
L' événement " dragleave " est déclenché lorsque le pointeur de la souris quitte la zone de déplacement du conteneur cible.
Ce qui a beaucoup de sens car dans de nombreux cas, seul le parent peut être largable et non les descendants. Je pense que event.stopPropogation () aurait dû gérer ce cas mais semble ne pas faire l'affaire.
Ci-dessus, certaines solutions semblent fonctionner pour la plupart des cas, mais échouent dans le cas des enfants qui ne prennent pas en charge les événements dragenter / dragleave , tels que iframe .
Une solution consiste à vérifier l' événement event.relatedTarget et à vérifier s'il se trouve à l'intérieur du conteneur, puis à ignorer l' événement dragleave comme je l'ai fait ici:
Vous pouvez trouver un violon qui fonctionne ici !
la source
Résolu ..!
Déclarez n'importe quel tableau par exemple:
Pas besoin de s'inquiéter des éléments enfants.
la source
J'ai beaucoup lutté avec cela, même après avoir lu toutes ces réponses, et j'ai pensé que je pourrais partager ma solution avec vous, parce que je pensais que ce pourrait être l'une des approches les plus simples, quelque peu différente cependant. Ma pensée était simplement d'omettre
dragleave
complètement l'écouteur d'événements et de coder le comportement de glisser-déplacer avec chaque nouvel événement dragenter déclenché, tout en s'assurant que les événements dragenter ne soient pas déclenchés inutilement.Dans mon exemple ci-dessous, j'ai une table, où je veux pouvoir échanger le contenu des lignes de table entre elles via l'API glisser-déposer. Le
dragenter
, une classe CSS doit être ajoutée à l'élément de ligne dans lequel vous faites actuellement glisser votre élément, pour le mettre en surbrillance, et surdragleave
, cette classe doit être supprimée.Exemple:
Tableau HTML très basique:
Et la fonction de gestionnaire d'événements dragenter, a ajouté sur chaque cellule de table ( à part
dragstart
,dragover
,drop
et lesdragend
gestionnaires qui ne sont pas spécifiques à cette question, donc pas copiés ici):Commentaires très basiques laissés dans le code, tels que ce code convient aussi aux débutants. Espérons que cela va vous aider! Notez que vous devrez bien sûr ajouter tous les écouteurs d'événement que j'ai mentionnés ci-dessus sur chaque cellule du tableau pour que cela fonctionne.
la source
Voici une autre approche basée sur le calendrier des événements.
L'
dragenter
événement distribué à partir de l'élément enfant peut être capturé par l'élément parent et il se produit toujours avant ledragleave
. Le délai entre ces deux événements est vraiment court, plus court que toute action possible de la souris humaine. Donc, l'idée est de mémoriser le moment où un événement sedragenter
produit et de filtrer lesdragleave
événements qui se produisent "pas trop rapidement" après ...Ce court exemple fonctionne sur Chrome et Firefox:
la source
pimvdb ..
Pourquoi n'essayez-vous pas d'utiliser drop au lieu de dragleave . Ça a marché pour moi. J'espère que ceci résoudra votre problème.
Veuillez vérifier le jsFiddle: http://jsfiddle.net/HU6Mk/118/
la source
Vous pouvez utiliser un délai d'expiration avec un
transitioning
indicateur et écouter l'élément supérieur.dragenter
/dragleave
des événements enfants bouillonnent jusqu'au conteneur.Étant donné que
dragenter
l'élément enfant se déclenche avantdragleave
le conteneur, nous définirons l'indicateur comme transition pendant 1 ms ... l'dragleave
auditeur vérifiera l'indicateur avant que le 1 ms ne soit écoulé.L'indicateur ne sera vrai que pendant les transitions vers les éléments enfants et ne sera pas vrai lors de la transition vers un élément parent (du conteneur)
jsfiddle: http://jsfiddle.net/ilovett/U7mJj/
la source
Vous devez supprimer les événements de pointeur pour tous les objets enfants de la cible de glissement.
la source