J'ai quelques menus HTML, que je montre complètement lorsqu'un utilisateur clique sur la tête de ces menus. Je voudrais masquer ces éléments lorsque l'utilisateur clique en dehors de la zone des menus.
Est-ce que quelque chose comme ça est possible avec jQuery?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
javascript
jquery
click
Sergio del Amo
la source
la source
event.target
et sansevent.stopPropagation
.Réponses:
Attachez un événement de clic au corps du document qui ferme la fenêtre. Attachez un événement de clic distinct au conteneur qui arrête la propagation vers le corps du document.
la source
$('html').click()
pas utiliser le corps. Le corps a toujours la hauteur de son contenu. Il n'y a pas beaucoup de contenu ou l'écran est très haut, cela ne fonctionne que sur la partie remplie par le corps.Vous pouvez écouter un événement de clic sur
document
puis vous assurer qu'il#menucontainer
n'est pas un ancêtre ou la cible de l'élément cliqué à l'aide de.closest()
.Si ce n'est pas le cas, l'élément cliqué est en dehors de
#menucontainer
et vous pouvez le masquer en toute sécurité.Éditer - 23/06/2017
Vous pouvez également nettoyer après l'écouteur d'événements si vous prévoyez de fermer le menu et que vous souhaitez arrêter d'écouter les événements. Cette fonction nettoiera uniquement l'écouteur nouvellement créé, en préservant tous les autres écouteurs de clic
document
. Avec la syntaxe ES2015:Éditer - 2018-03-11
Pour ceux qui ne veulent pas utiliser jQuery. Voici le code ci-dessus dans plain vanillaJS (ECMAScript6).
REMARQUE: Ceci est basé sur le commentaire d'Alex à utiliser simplement à la
!element.contains(event.target)
place de la partie jQuery.Mais
element.closest()
est désormais également disponible dans tous les principaux navigateurs (la version W3C diffère un peu de celle de jQuery). Les polyfills peuvent être trouvés ici: Element.closest ()Éditer - 2020-05-21
Dans le cas où vous souhaitez que l'utilisateur puisse cliquer et faire glisser à l'intérieur de l'élément, puis relâchez la souris à l'extérieur de l'élément, sans fermer l'élément:
Et dans
outsideClickListener
:la source
!element.contains(event.target)
utilisant Node.contains ()La raison pour laquelle cette question est si populaire et a tant de réponses est qu'elle est d'une complexité trompeuse. Après près de huit ans et des dizaines de réponses, je suis véritablement surpris de voir le peu de soin accordé à l'accessibilité.
C'est une noble cause et c'est le vrai problème. Le titre de la question - qui est ce à quoi la plupart des réponses semblent tenter de répondre - contient un triste hareng rouge.
Astuce: c'est le mot "clic" !
Vous ne voulez pas réellement lier les gestionnaires de clic.
Si vous liez des gestionnaires de clics pour fermer la boîte de dialogue, vous avez déjà échoué. La raison pour laquelle vous avez échoué est que tout le monde ne déclenche pas d'
click
événements. Les utilisateurs n'utilisant pas de souris pourront échapper à votre boîte de dialogue (et votre menu contextuel est sans doute un type de boîte de dialogue) en appuyant sur Tab, et ils ne pourront alors pas lire le contenu derrière la boîte de dialogue sans déclencher par la suite unclick
événement.Alors reformulons la question.
Tel est l'objectif. Malheureusement, nous devons maintenant lier
userisfinishedwiththedialog
événement, et cette liaison n'est pas si simple.Alors, comment pouvons-nous détecter qu'un utilisateur a fini d'utiliser une boîte de dialogue?
focusout
un événementUn bon début consiste à déterminer si le focus a quitté la boîte de dialogue.
Astuce: soyez prudent avec l'
blur
événement,blur
ne se propage pas si l'événement était lié à la phase bouillonnante!jQuery
focusout
fera très bien. Si vous ne pouvez pas utiliser jQuery, vous pouvez utiliserblur
pendant la phase de capture:De plus, pour de nombreuses boîtes de dialogue, vous devrez permettre au conteneur de se concentrer. Ajoutez
tabindex="-1"
pour permettre à la boîte de dialogue de recevoir le focus de manière dynamique sans interrompre le flux de tabulation.Si vous jouez avec cette démo pendant plus d'une minute, vous devriez rapidement commencer à voir des problèmes.
Le premier est que le lien dans la boîte de dialogue n'est pas cliquable. Tenter de cliquer dessus ou sur un onglet entraînera la fermeture de la boîte de dialogue avant que l'interaction n'ait lieu. En effet, la focalisation de l'élément interne déclenche un
focusout
événement avant de déclencher unefocusin
nouveau événement.Le correctif consiste à mettre en file d'attente le changement d'état sur la boucle d'événements. Cela peut être fait en utilisant
setImmediate(...)
ousetTimeout(..., 0)
pour les navigateurs qui ne prennent pas en chargesetImmediate
. Une fois mis en file d'attente, il peut être annulé par un autrefocusin
:Afficher l'extrait de code
Le deuxième problème est que la boîte de dialogue ne se ferme pas lorsque le lien est enfoncé à nouveau. En effet, la boîte de dialogue perd le focus, déclenchant le comportement de fermeture, après quoi le clic sur le lien déclenche la réouverture de la boîte de dialogue.
Comme pour le numéro précédent, l'état de mise au point doit être géré. Étant donné que le changement d'état a déjà été mis en file d'attente, il s'agit simplement de gérer les événements de focus sur les déclencheurs de dialogue:
Cela devrait vous sembler familierAfficher l'extrait de code
Esc clé
Si vous pensiez avoir terminé en gérant les états de focus, vous pouvez faire plus pour simplifier l'expérience utilisateur.
C'est souvent une fonctionnalité "agréable à avoir", mais il est courant que lorsque vous avez un modal ou une popup de quelque sorte que ce soit, la Escclé la ferme.
Afficher l'extrait de code
Si vous savez que la boîte de dialogue contient des éléments pouvant être mis au point, vous n'aurez pas besoin de faire la mise au point directement. Si vous créez un menu, vous pouvez plutôt concentrer le premier élément de menu.
Afficher l'extrait de code
Rôles WAI-ARIA et autres supports d'accessibilité
J'espère que cette réponse couvre les bases de la prise en charge accessible du clavier et de la souris pour cette fonctionnalité, mais comme elle est déjà assez importante, je vais éviter toute discussion sur les rôles et les attributs WAI-ARIA , mais je recommande vivement aux implémenteurs de se référer à la spécification pour plus de détails. quels rôles ils devraient utiliser et tout autre attribut approprié.
la source
Les autres solutions ici ne fonctionnaient pas pour moi, j'ai donc dû utiliser:
la source
&& !$(event.target).parents("#foo").is("#foo")
à l'intérieur de l'IF
instruction afin qu'aucun élément enfant ne ferme le menu lorsque vous cliquez dessus..is('#foo, #foo *')
, mais je ne recommande pas de lier les gestionnaires de clics pour résoudre ce problème .!$(event.target).closest("#foo").length
serait mieux et évite d'avoir à ajouter @ honyovk.J'ai une application qui fonctionne de manière similaire à l'exemple d'Eran, sauf que j'attache l'événement click au corps lorsque j'ouvre le menu ... Un peu comme ceci:
Plus d'informations sur la
one()
fonction de jQueryla source
.one
- à l'intérieur du$('html')
gestionnaire - écrivez a$('html').off('click')
.one
gestionnaire appellera automatiquementoff
(comme indiqué dans les documents jQuery).Après la recherche, j'ai trouvé trois solutions de travail (j'ai oublié les liens de la page pour référence)
Première solution
Deuxième solution
Troisième solution
la source
document.getElementsByClassName
, si quelqu'un a un indice, partagez-le.Fonctionne très bien pour moi.
la source
#menucontainer
question était sur un clictabindex="-1"
au#menuscontainer
pour le faire fonctionner. Il semble que si vous placez une balise d'entrée à l'intérieur du conteneur et cliquez dessus, le conteneur est masqué.Maintenant, il y a un plugin pour cela: événements extérieurs ( article de blog )
Ce qui suit se produit lorsqu'un gestionnaire clickoutside (WLOG) est lié à un élément:
Ainsi, aucun événement n'est arrêté de la propagation et des gestionnaires de clics supplémentaires peuvent être utilisés "au-dessus" de l'élément avec le gestionnaire externe.
la source
$( '#element' ).on( 'clickoutside', function( e ) { .. } );
Cela a fonctionné parfaitement pour moi !!
la source
Je ne pense pas que ce dont vous avez vraiment besoin soit de fermer le menu lorsque l'utilisateur clique à l'extérieur; ce dont vous avez besoin, c'est que le menu se ferme lorsque l'utilisateur clique n'importe où sur la page. Si vous cliquez sur le menu, ou hors du menu, il devrait se fermer non?
Trouver aucune réponse satisfaisante ci-dessus m'a incité à écrire cet article de blog l'autre jour. Pour les plus pédants, il existe un certain nombre de pièges à noter:
body { margin-left:auto; margin-right: auto; width:960px;}
la source
Comme l'a dit une autre affiche, il y a beaucoup de pièges, surtout si l'élément que vous affichez (dans ce cas un menu) a des éléments interactifs. J'ai trouvé la méthode suivante assez robuste:
la source
Une solution simple à la situation est:
Le script ci-dessus masquera le
div
si en dehors de ladiv
déclenchement événement en événement click.Vous pouvez consulter le blog suivant pour plus d'informations: http://www.codecanal.com/detect-click-outside-div-using-javascript/
la source
Solution1
Au lieu d'utiliser event.stopPropagation () qui peut avoir des effets secondaires, définissez simplement une variable d'indicateur simple et ajoutez une
if
condition. J'ai testé cela et travaillé correctement sans aucun effet secondaire de stopPropagation:Solution2
Avec juste une
if
condition simple :la source
Vérifiez la cible de l'événement de clic sur la fenêtre (elle doit se propager à la fenêtre, tant qu'elle n'est capturée nulle part ailleurs), et assurez-vous qu'il ne s'agit d'aucun des éléments de menu. Si ce n'est pas le cas, alors vous êtes en dehors de votre menu.
Ou vérifiez la position du clic et voyez s'il est contenu dans la zone de menu.
la source
J'ai eu du succès avec quelque chose comme ça:
La logique est la suivante: lorsque
#menuscontainer
s'affiche, liez un gestionnaire de clic au corps qui#menuscontainer
ne se cache que si la cible (du clic) n'en est pas un enfant.la source
En variante:
Il n'a aucun problème avec l' arrêt de la propagation des événements et prend mieux en charge plusieurs menus sur la même page où cliquer sur un deuxième menu alors qu'un premier est ouvert laissera le premier ouvert dans la solution stopPropagation.
la source
L'événement possède une propriété appelée event.path de l'élément qui est une "liste ordonnée statique de tous ses ancêtres dans un arbre" . Pour vérifier si un événement provient d'un élément DOM spécifique ou de l'un de ses enfants, vérifiez simplement le chemin d'accès à cet élément DOM spécifique. Il peut également être utilisé pour vérifier plusieurs éléments en exécutant logiquement
OR
la vérification des éléments dans lasome
fonction.Donc, pour votre cas, cela devrait être
la source
event.path
n'est pas une chose.J'ai trouvé cette méthode dans un plugin de calendrier jQuery.
la source
Voici la solution JavaScript vanille pour les futurs téléspectateurs.
Lorsque vous cliquez sur un élément du document, si l'ID de l'élément cliqué est basculé, ou que l'élément caché n'est pas masqué et que l'élément caché ne contient pas l'élément cliqué, basculez l'élément.
Afficher l'extrait de code
Si vous allez avoir plusieurs bascules sur la même page, vous pouvez utiliser quelque chose comme ceci:
hidden
à l'élément pliable.la source
Je suis surpris que personne n'ait reconnu l'
focusout
événement:la source
Si vous créez des scripts pour IE et FF 3. * et que vous voulez simplement savoir si le clic s'est produit dans une certaine zone de boîte, vous pouvez également utiliser quelque chose comme:
la source
Au lieu d'utiliser l'interruption de flux, un événement flou / focus ou toute autre technique délicate, faites simplement correspondre le flux d'événements avec la parenté de l'élément:
Pour supprimer l'écouteur d'événements hors clic, il suffit de:
la source
#menuscontainer
vous passez encore par ses parents. vous devez d'abord vérifier cela, et si ce n'est pas cet élément, puis remonter l'arborescence DOM.if(!($(event.target).is("#menuscontainer") || $(event.target).parents().is("#menuscontainer"))){
. C'est une minuscule optimisation, mais qui ne se produit que quelques fois dans la durée de vie de votre programme: pour chaque clic, si l'click.menu-outside
événement est enregistré. Il est plus long (+32 caractères) et n'utilise pas de chaînage de méthodeUtilisation:
la source
Si quelqu'un est curieux, voici la solution javascript (es6):
et es5, juste au cas où:
});
la source
Voici une solution simple en pur javascript. Il est à jour avec ES6 :
la source
() => {}
placefunction() {}
. Ce que vous avez là-bas est classé comme JavaScript simple avec une touche d'ES6.Accrochez un écouteur d'événement de clic sur le document. À l'intérieur de l'écouteur d'événement, vous pouvez regarder l' objet événement , en particulier, event.target pour voir quel élément a été cliqué:
la source
J'ai utilisé le script ci-dessous et fait avec jQuery.
Trouvez ci-dessous le code HTML
Vous pouvez lire le tutoriel ici
la source
Si vous cliquez sur le document, masquez un élément donné, sauf si vous cliquez sur ce même élément.
la source
Votez pour la réponse la plus populaire, mais ajoutez
donc, un clic sur une barre de défilement ne [cache pas ou quoi que ce soit] votre élément cible.
la source
Pour une utilisation plus facile et un code plus expressif, j'ai créé un plugin jQuery pour cela:
Remarque: la cible est l'élément sur lequel l'utilisateur a réellement cliqué. Mais le rappel est toujours exécuté dans le contexte de l'élément d' origine, de sorte que vous pouvez utiliser ce que vous attendez d'un rappel de jQuery.
Brancher:
Par défaut, l'écouteur d'événements Click est placé sur le document. Cependant, si vous souhaitez limiter la portée de l'écouteur d'événements, vous pouvez passer un objet jQuery représentant un élément de niveau parent qui sera le parent supérieur auquel les clics seront écoutés. Cela empêche les écouteurs d'événements de niveau document inutiles. De toute évidence, cela ne fonctionnera que si l'élément parent fourni est un parent de votre élément initial.
Utilisez comme ça:
la source