Aperçu
J'ai la structure HTML suivante et j'ai attaché les événements dragenter
et dragleave
à l' <div id="dropzone">
élément.
<div id="dropzone">
<div id="dropzone-content">
<div id="drag-n-drop">
<div class="text">this is some text</div>
<div class="text">this is a container with text and images</div>
</div>
</div>
</div>
Problème
Lorsque je fais glisser un fichier sur le <div id="dropzone">
, l' dragenter
événement est déclenché comme prévu. Cependant, lorsque je déplace ma souris sur un élément enfant, tel que <div id="drag-n-drop">
, l' dragenter
événement est déclenché pour l' <div id="drag-n-drop">
élément, puis l' dragleave
événement est déclenché pour l' <div id="dropzone">
élément.
Si je survole à <div id="dropzone">
nouveau l' élément, l' dragenter
événement est à nouveau déclenché, ce qui est cool, mais l' dragleave
événement est déclenché pour l'élément enfant qui vient de quitter, donc l' removeClass
instruction est exécutée, ce qui n'est pas cool.
Ce comportement est problématique pour 2 raisons:
Je m'attache seulement
dragenter
&dragleave
au<div id="dropzone">
donc je ne comprends pas pourquoi les éléments enfants ont ces événements attachés aussi bien.Je traîne toujours sur l'
<div id="dropzone">
élément tout en survolant ses enfants donc je ne veuxdragleave
pas tirer!
jsFiddle
Voici un jsFiddle à bricoler: http://jsfiddle.net/yYF3S/2/
Question
Alors ... comment puis-je faire en sorte que lorsque je fais glisser un fichier sur l' <div id="dropzone">
élément, dragleave
ne se déclenche pas même si je traîne sur des éléments enfants ... il ne devrait se déclencher que lorsque je quitte l' <div id="dropzone">
élément ... . le survol / le glissement n'importe où dans les limites de l'élément ne doit pas déclencher l' dragleave
événement.
J'ai besoin que cela soit compatible avec tous les navigateurs, au moins dans les navigateurs prenant en charge le glisser-déposer HTML5, donc cette réponse n'est pas adéquate.
Il semble que Google et Dropbox aient compris cela, mais leur code source est minifié / complexe, donc je n'ai pas été en mesure de comprendre cela à partir de leur implémentation.
e.stopPropagation();
Réponses:
Si vous n'avez pas besoin de lier des événements aux éléments enfants, vous pouvez toujours utiliser la propriété pointer-events.
la source
:hover
styles séparés ou de gestionnaires d'événements de clic). Si vous souhaitez conserver ces événements, voici une autre solution de contournement que j'ai utilisée: bensmithett.github.io/dragster.dropzone * {pointer-events: none;}
$('.element').addClass('dragging-over')
pour l'élément que vous faites glisser, et$('.element').removeClass('dragging-over')
lorsque vous faites glisser. Ensuite, dans votre CSS, vous pouvez avoir.element.dragging-over * { pointer-events: none; }
. Cela supprime les événements de pointeur de tous les éléments enfants uniquement lorsque vous faites glisser.J'ai finalement trouvé une solution qui me satisfait. En fait, j'ai trouvé plusieurs façons de faire ce que je veux mais aucune n'a été aussi réussie que la solution actuelle ... dans une solution, j'ai connu des scintillements fréquents à la suite de l'ajout / suppression d'une bordure à l'
#dropzone
élément ... dans une autre, la bordure n'a jamais été supprimé si vous vous éloignez du navigateur.Quoi qu'il en soit, ma meilleure solution hacky est la suivante:
Cela fonctionne plutôt bien mais des problèmes sont survenus dans Firefox car Firefox invoquait deux fois
dragenter
donc mon compteur était désactivé. Mais néanmoins, ce n'est pas une solution très élégante.Ensuite, je suis tombé sur cette question: Comment détecter l'événement dragleave dans Firefox lors du glissement hors de la fenêtre
J'ai donc pris la réponse et l' ai appliquée à ma situation:
C'est propre et élégant et semble fonctionner dans tous les navigateurs que j'ai testés jusqu'à présent (je n'ai pas encore testé IE).
la source
stopPropagation()
etpreventDefault()
est préféré. Je laisserais tomber lereturn false
.C'est un peu moche mais ça marche bon sang! ...
Sur votre gestionnaire 'dragenter', stockez event.target (dans une variable à l'intérieur de votre fermeture, ou autre), puis dans votre gestionnaire 'dragleave' ne lancez votre code que si event.target === celui que vous avez stocké.
Si votre 'dragenter' se déclenche lorsque vous ne le souhaitez pas (c'est-à-dire lorsqu'il entre après avoir quitté des éléments enfants), la dernière fois qu'il se déclenche avant que la souris ne quitte le parent, c'est sur le parent, donc le parent sera toujours le «dragenter» final avant le «dragleave» prévu.
la source
Au début, j'étais d'accord avec les gens qui rejetaient l'
pointer-events: none
approche. Mais ensuite je me suis demandé:Dans mon cas, j'ai beaucoup de choses en cours dans les enfants, par exemple, survoler pour afficher des boutons pour des actions supplémentaires, l'édition en ligne, etc. Cependant, rien de tout cela n'est nécessaire ou même souhaité lors d' un glisser.
Dans mon cas, j'utilise quelque chose comme ceci pour désactiver les événements de pointeur de manière sélective pour tous les nœuds enfants du conteneur parent:
Utilisez votre approche préférée pour ajouter / supprimer la classe
dragging-in-progress
dans les gestionnairesdragEnter
/dragLeave
event, comme je l'ai fait ou faites de même dansdragStart
, et. Al.la source
dragstart
événement et supprimez-ladragend
.Cela semble être un bogue de Chrome.
La seule solution de contournement à laquelle je pouvais penser était de créer un élément de superposition transparent pour capturer vos événements: http://jsfiddle.net/yYF3S/10/
JS :
HTML :
la source
Le problème est que vos éléments à l'intérieur des dropzones font bien sûr partie de la dropzone et lorsque vous entrez les enfants, vous quittez le parent. Résoudre ce problème n'est pas facile. Vous pouvez également essayer d'ajouter des événements aux enfants en ajoutant à nouveau votre classe au parent.
Vos événements se déclencheront toujours plusieurs fois mais personne ne le verra.
// Edit: utilisez l'événement dragmove pour écraser définitivement l'événement dragleave:
Définissez l'événement dragleave uniquement pour la zone de dépôt.
la source
dragleave
... quand je quitte un enfant, je suis peut-être toujours dans le parent,#dropzone
mais cela ne déclenchera pas àdragenter
nouveau l' événement :(dragleave
événement est déclenché pour l'élément enfant juste à gauche, donc à nouveau l'removeClass
instruction est exécutéedragleave
uniquement pour le#dropzone
... si je pouvais, je n'aurais pas ce problème.Comme benr l'a mentionné dans cette réponse , vous pouvez empêcher les nœuds enfants de se déclencher sur des événements, mais si vous devez lier certains événements, procédez comme suit :
Et ajoutez celui-ci à votre code JS:
la source
Si vous utilisez jQuery, vérifiez ceci: https://github.com/dancork/jquery.event.dragout
C'est vraiment génial.
EDIT: en fait, je ne pense pas que cela dépende de jQuery, vous pouvez probablement simplement utiliser le code même sans.
la source
dragleave
même si je n'ai pas quitté la zone de dépôt parent.dragout
c'était la seule solution qui fonctionnait pour moi.@hristo J'ai une solution beaucoup plus élégante. Vérifiez que si c'est quelque chose que vous pourriez utiliser.
Vos efforts n'ont pas été vains après tout. J'ai réussi à utiliser le vôtre au début, mais j'ai eu différents problèmes dans FF, Chrome. Après avoir passé tant d'heures, cette suggestion a fonctionné exactement comme prévu.
Voici comment se déroule la mise en œuvre. J'ai également profité des repères visuels pour guider correctement les utilisateurs sur la zone de dépôt.
la source
var dropZoneHideDelay=70, dropZoneVisible=true;
dropZoneHideDelay, dropZoneVisible
sont nécessaires à travers deux'on'
événements de document dans ma mise en œuvre.Mes deux cents: Cachez un calque sur votre zone de dépôt, puis affichez-le lorsque vous faites glisser et ciblez le dragleave dessus.
Démo: https://jsfiddle.net/t6q4shat/
HTML
CSS
JS
la source
Donc pour moi, l'approche
pointer-events: none;
n'a pas très bien fonctionné ... Voici donc ma solution alternative:De cette façon, il n'est pas possible au
dragleave
parent (sur un enfant) oudragover
un élément enfant. J'espère que cela t'aides :)* La classe '.active' que j'ajoute quand je
dragenter
oudragleave
. Mais si vous travaillez sans cela, laissez la classe à l'écart.la source
Solution rapide super simple pour cela, non testée de manière approfondie mais fonctionne actuellement dans Chrome.
Excusez le Coffeescript.
Cela corrige le bogue de scintillement de Chrome, ou du moins la permutation de celui-ci qui me causait des problèmes.
la source
Cette réponse peut être trouvée ici:
Dragleave HTML5 déclenché lors du survol d'un élément enfant
la source
Ma version:
Avec cette disposition:
Je l' ai fait une décharge de classes d'éléments pour
e.target
,e.currentTarget
,e.relatedTarget
pour les deuxdragover
etdragleave
les événements.Cela m'a montré qu'en quittant le bloc parent (
.dropzone
)e.relatedTarget
n'est pas un enfant de ce bloc, donc je sais que je suis hors de la zone de dépôt.la source
Ici, une des solutions les plus simples ● ︿ ●
Jetez un œil à ce violon <- essayez de faire glisser un fichier dans la boîte
Vous pouvez faire quelque chose comme ceci:
Par cela, vous devriez déjà savoir ce qui se passe ici.
Jetez un œil au violon, vous savez.
la source
J'ai eu un problème similaire et je l'ai résolu de cette façon:
Le problème: La fonction drop (ev) est déclenchée lorsque l'utilisateur dépose un élément dans la "drop zone" (élément ul), mais malheureusement aussi lorsque l'élément est déposé dans l'un de ses enfants (éléments li).
Le correctif:
la source
J'essayais de l'implémenter moi-même pour une boîte de téléchargement de fichiers où la couleur de la boîte changerait lorsque les utilisateurs faisaient glisser un fichier dans l'espace.
J'ai trouvé une solution qui est un bon mélange de Javascript et de CSS. Supposons que vous ayez une zone de dépôt
div
avec identifiant#drop
. Ajoutez ceci à votre Javascript:Ensuite, ajoutez ceci à votre CSS, pour désactiver tous les enfants classera
.inactive
:Ainsi, les éléments enfants seront inactifs tant que l'utilisateur fera glisser l'élément sur la boîte.
la source
Je ne me suis senti satisfait d'aucune des solutions de contournement présentées ici, car je ne veux pas perdre le contrôle des éléments enfants.
J'ai donc utilisé une approche logique différente, en la traduisant en un plugin jQuery, appelé jquery-draghandler . Il ne manipule absolument pas le DOM, garantissant des performances élevées. Son utilisation est simple:
Il traite parfaitement le problème sans compromettre aucune fonctionnalité DOM.
Téléchargement, détails et explications sur son référentiel Git .
la source
frame
s et que votre élément est à la frontière de celui-ci. Dans ce cas, je ne suggère pas cette approche.J'aime vraiment ce que je vois https://github.com/lolmaus/jquery.dragbetter/mais voulait partager une alternative possible. Ma stratégie générale était d'appliquer un style d'arrière-plan à la zone de dépôt (et non à ses enfants) lors de son entrée par glisser-déposer ou de l'un de ses enfants (via le bullage). Ensuite, je supprime le style lors du glissement de la zone de dépôt. L'idée était lors du passage à un enfant, même si je supprimais le style de la zone de dépôt en le quittant (le dragleave se déclenche), je réappliquerais simplement le style à la zone de dépôt parent en introduisant un enfant par glisser-déposer. Le problème est bien sûr que lors du passage de la zone de dépôt à un enfant de la zone de dépôt, le dragenter est déclenché sur l'enfant avant le dragleave, donc mes styles ont été appliqués dans le désordre. La solution pour moi était d'utiliser une minuterie pour forcer l'événement dragenter à revenir dans la file d'attente des messages, me permettant de le traiter APRÈS le dragleave. J'ai utilisé une fermeture pour accéder à l'événement sur le rappel du minuteur.
Cela semble fonctionner dans Chrome, c'est-à-dire Firefox et fonctionne quel que soit le nombre d'enfants dans la zone de dépôt. Je suis un peu inquiet quant au délai d'attente garantissant le reséquençage des événements, mais cela semble fonctionner plutôt bien pour mon cas d'utilisation.
la source
J'essayais de l'implémenter moi-même, et je ne voulais pas non plus de Jquery ou de tout autre plugin.
Je voulais gérer le téléchargement du fichier, de la manière la plus appropriée pour moi:
Structure des fichiers:
--- / uploads {répertoire de téléversements}
--- /js/slyupload.js {fichier javascript.}
--- index.php
--- upload.php
--- styles.css {juste un peu de style ..}
Code HTML:
Ensuite, voici le fichier Javascript attaché :: 'js / slyupload.js'
CSS:
la source
Désolé, ce n'est pas javascript jquery, mais pour moi, c'est le moyen le plus logique de résoudre ce problème. Le navigateur devrait appeler dropleave (de l'élément précédent) avant dropenter (du nouvel élément, comme quelque chose ne peut pas entrer autre chose avant d'avoir quitté la première chose, je ne comprends pas pourquoi ils l'ont fait! Il vous suffit donc de retarder de dropleave comme ça:
Et le dropenter se produira après le dropleave, c'est tout!
la source
Utilisez le
greedy : true
à l'enfant en fonction dedroppable
. Ensuite, démarrez uniquement l'événement cliqué sur la première couche.la source