Ich habe einige HTML-Menüs, die ich vollständig zeige, wenn ein Benutzer auf den Kopf dieser Menüs klickt. Ich möchte diese Elemente ausblenden, wenn der Benutzer außerhalb des Menübereichs klickt.
Ist so etwas mit jQuery möglich?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
javascript
jquery
click
Sergio del Amo
quelle
quelle
event.target
und ohneevent.stopPropagation
.Antworten:
Fügen Sie dem Dokumentkörper ein Klickereignis hinzu, das das Fenster schließt. Fügen Sie dem Container ein separates Klickereignis hinzu, das die Weitergabe an den Dokumentkörper stoppt.
quelle
$('html').click()
nicht Körper verwenden. Der Körper hat immer die Höhe seines Inhalts. Wenn es nicht viel Inhalt gibt oder der Bildschirm sehr hoch ist, funktioniert er nur an dem Teil, den der Körper ausfüllt.Sie können auf ein Klickereignis warten
document
und dann#menucontainer
mithilfe von sicherstellen, dass es sich nicht um einen Vorfahren oder das Ziel des angeklickten Elements handelt.closest()
.Ist dies nicht der Fall, befindet sich das angeklickte Element außerhalb des
#menucontainer
und Sie können es sicher ausblenden.Bearbeiten - 2017-06-23
Sie können auch nach dem Ereignis-Listener bereinigen, wenn Sie das Menü schließen möchten und nicht mehr auf Ereignisse warten möchten. Diese Funktion bereinigt nur den neu erstellten Listener und behält alle anderen Klick-Listener bei
document
. Mit ES2015-Syntax:Bearbeiten - 2018-03-11
Für diejenigen, die jQuery nicht verwenden möchten. Hier ist der obige Code in einfachem vanillaJS (ECMAScript6).
HINWEIS: Dies basiert auf einem Alex-Kommentar, der nur verwendet werden soll
!element.contains(event.target)
anstelle des jQuery-Teils verwendet wird.Ist
element.closest()
jetzt aber auch in allen gängigen Browsern verfügbar (die W3C-Version unterscheidet sich ein wenig von der jQuery-Version). Polyfills finden Sie hier: Element.closest ()Bearbeiten - 2020-05-21
Wenn Sie möchten, dass der Benutzer innerhalb des Elements klicken und ziehen kann, lassen Sie die Maus außerhalb des Elements los, ohne das Element zu schließen:
Und in
outsideClickListener
:quelle
!element.contains(event.target)
mit Node.contains ()Der Grund, warum diese Frage so beliebt ist und so viele Antworten hat, ist, dass sie täuschend komplex ist. Nach fast acht Jahren und Dutzenden von Antworten bin ich wirklich überrascht zu sehen, wie wenig Sorgfalt auf die Zugänglichkeit gelegt wurde.
Dies ist eine edle Sache und die tatsächliche Problem. Der Titel der Frage - was die meisten Antworten zu beantworten scheinen - enthält einen unglücklichen roten Hering.
Hinweis: Es ist das Wort "Klick" !
Sie möchten eigentlich keine Klick-Handler binden.
Wenn Sie Click-Handler binden, um das Dialogfeld zu schließen, sind Sie bereits gescheitert. Der Grund, warum Sie versagt haben, ist, dass nicht jeder
click
Ereignisse auslöst . Benutzer, die keine Maus verwenden, können Ihren Dialog durch Drücken von verlassen (und Ihr Popup-Menü ist wohl eine Art Dialog) Tabund können dann den Inhalt hinter dem Dialog nicht lesen, ohne anschließend einclick
Ereignis auszulösen .Lassen Sie uns die Frage umformulieren.
Das ist das Ziel. Leider müssen wir jetzt das
userisfinishedwiththedialog
Ereignis binden , und diese Bindung ist nicht so einfach.Wie können wir also feststellen, dass ein Benutzer die Verwendung eines Dialogfelds beendet hat?
focusout
VeranstaltungEin guter Anfang ist festzustellen, ob der Fokus den Dialog verlassen hat.
Hinweis: Seien Sie vorsichtig mit dem
blur
Ereignis, verbreiten Sieblur
sich nicht, wenn das Ereignis an die Blasenphase gebunden war!jQuery's
focusout
wird gut funktionieren. Wenn Sie jQuery nicht verwenden können, können Sieblur
während der Erfassungsphase Folgendes verwenden:Außerdem müssen Sie für viele Dialoge zulassen, dass der Container den Fokus erhält. Hinzufügen
tabindex="-1"
, damit der Dialog dynamisch den Fokus erhält, ohne den Tabulatorfluss zu unterbrechen.Wenn Sie länger als eine Minute mit dieser Demo spielen, sollten Sie schnell Probleme sehen.
Der erste ist, dass der Link im Dialogfeld nicht anklickbar ist. Wenn Sie versuchen, darauf oder auf die Registerkarte zu klicken, wird der Dialog geschlossen, bevor die Interaktion stattfindet. Dies liegt daran, dass das Fokussieren des inneren Elements ein
focusout
Ereignis auslöst , bevor a ausgelöst wirdfocusin
Ereignis erneut wird.Das Update besteht darin, die Statusänderung in der Ereignisschleife in die Warteschlange zu stellen. Dies kann mithilfe von
setImmediate(...)
odersetTimeout(..., 0)
für Browser erfolgen, die dies nicht unterstützensetImmediate
. Sobald es in der Warteschlange steht, kann es durch eine nachfolgende gelöscht werdenfocusin
:Code-Snippet anzeigen
Das zweite Problem ist, dass der Dialog nicht geschlossen wird, wenn der Link erneut gedrückt wird. Dies liegt daran, dass der Dialog den Fokus verliert und das Schließverhalten auslöst. Danach löst der Linkklick den Dialog zum erneuten Öffnen aus.
Ähnlich wie in der vorherigen Ausgabe muss der Fokusstatus verwaltet werden. Da die Statusänderung bereits in die Warteschlange gestellt wurde, müssen nur Fokusereignisse in den Dialogauslösern behandelt werden:
Das sollte vertraut aussehenCode-Snippet anzeigen
Esc Schlüssel
Wenn Sie dachten, Sie wären mit der Behandlung der Fokuszustände fertig, können Sie noch mehr tun, um die Benutzererfahrung zu vereinfachen.
Dies ist oft eine "nice to have" -Funktion, aber es ist üblich, dass der EscSchlüssel es schließt , wenn Sie ein Modal oder Popup irgendeiner Art haben.
Code-Snippet anzeigen
Wenn Sie wissen, dass Sie fokussierbare Elemente im Dialogfeld haben, müssen Sie das Dialogfeld nicht direkt fokussieren. Wenn Sie ein Menü erstellen, können Sie stattdessen den ersten Menüpunkt fokussieren.
Code-Snippet anzeigen
WAI-ARIA-Rollen und andere Unterstützung für Barrierefreiheit
Diese Antwort behandelt hoffentlich die Grundlagen der barrierefreien Tastatur- und Mausunterstützung für diese Funktion, aber da sie bereits ziemlich umfangreich ist, werde ich jede Diskussion über WAI-ARIA-Rollen und -Attribute vermeiden. Ich empfehle jedoch dringend , dass Implementierer sich für Einzelheiten auf die Spezifikation beziehen auf welche Rollen sie verwenden sollten und welche anderen geeigneten Attribute.
quelle
Die anderen Lösungen hier haben bei mir nicht funktioniert, daher musste ich Folgendes verwenden:
quelle
&& !$(event.target).parents("#foo").is("#foo")
innerhalb derIF
Anweisung hinzugefügt habe , damit untergeordnete Elemente das Menü beim Klicken nicht schließen..is('#foo, #foo *')
, ich empfehle jedoch nicht, Klick-Handler zu binden, um dieses Problem zu lösen .!$(event.target).closest("#foo").length
wäre besser und macht die Hinzufügung von @ honyovk überflüssig.Ich habe eine Anwendung, die ähnlich wie Erans Beispiel funktioniert, außer dass ich das Klickereignis beim Öffnen des Menüs an den Text anhänge ... Ein bisschen wie folgt:
Weitere Informationen zur Funktion von jQuery
one()
quelle
.one
- innerhalb des$('html')
Handlers - schreiben Sie a$('html').off('click')
.one
Handler ruft automatisch aufoff
(wie in den jQuery-Dokumenten gezeigt).Nach Recherchen habe ich drei funktionierende Lösungen gefunden (ich habe die Seitenlinks als Referenz vergessen)
Erste Lösung
Zweite Lösung
Dritte Lösung
quelle
document.getElementsByClassName
Wenn jemand eine Ahnung hat, teilen Sie diese bitte mit.Funktioniert bei mir ganz gut.
quelle
#menucontainer
Frage war über einen Klicktabindex="-1"
um das ,#menuscontainer
damit es funktioniert. Es scheint, dass der Container ausgeblendet wird, wenn Sie ein Eingabe-Tag in den Container einfügen und darauf klicken.Jetzt gibt es dafür ein Plugin: Externe Events ( Blogpost )
Folgendes passiert, wenn ein Clickoutside- Handler (WLOG) an ein Element gebunden ist:
Daher werden keine Ereignisse an der Weitergabe gehindert, und zusätzliche Klick- Handler können "über" dem Element mit dem Außen-Handler verwendet werden.
quelle
$( '#element' ).on( 'clickoutside', function( e ) { .. } );
Das hat bei mir perfekt funktioniert !!
quelle
Ich glaube nicht, dass Sie das Menü wirklich schließen müssen, wenn der Benutzer nach draußen klickt. Sie müssen das Menü schließen, wenn der Benutzer auf eine beliebige Stelle auf der Seite klickt. Wenn Sie auf das Menü klicken oder das Menü verlassen, sollte es geschlossen werden, oder?
Da ich oben keine zufriedenstellenden Antworten gefunden habe, habe ich neulich diesen Blog-Beitrag geschrieben . Für die pedantischeren gibt es eine Reihe von Fallstricken zu beachten:
body { margin-left:auto; margin-right: auto; width:960px;}
quelle
Wie ein anderes Poster sagte, gibt es viele Fallstricke, insbesondere wenn das Element, das Sie anzeigen (in diesem Fall ein Menü), interaktive Elemente enthält. Ich habe festgestellt, dass die folgende Methode ziemlich robust ist:
quelle
Eine einfache Lösung für die Situation ist:
Das obige Skript verbirgt das
div
if außerhalb desdiv
Auslösen, Klickereignisses ausgelöst wird.Weitere Informationen finden Sie im folgenden Blog: http://www.codecanal.com/detect-click-outside-div-using-javascript/
quelle
Lösung1
Anstatt event.stopPropagation () zu verwenden, das einige Nebenwirkungen haben kann, definieren Sie einfach eine einfache Flag-Variable und fügen Sie eine
if
Bedingung hinzu. Ich habe dies getestet und ohne Nebenwirkungen von stopPropagation richtig gearbeitet:Lösung2
Mit nur einer einfachen
if
Bedingung:quelle
Überprüfen Sie das Fensterklick-Ereignisziel (es sollte sich auf das Fenster ausbreiten, solange es nirgendwo anders erfasst wird) und stellen Sie sicher, dass es keines der Menüelemente ist. Wenn nicht, befinden Sie sich außerhalb Ihres Menüs.
Oder überprüfen Sie die Position des Klicks und prüfen Sie, ob er im Menübereich enthalten ist.
quelle
Ich hatte Erfolg mit so etwas:
Die Logik lautet: Wenn
#menuscontainer
angezeigt wird, binden Sie einen Klick-Handler an den Körper, der sich#menuscontainer
nur verbirgt , wenn das Ziel (des Klicks) kein Kind davon ist.quelle
Als Variante:
Es hat kein Problem mit dem Stoppen der Ereignisweitergabe und unterstützt besser mehrere Menüs auf derselben Seite, bei denen durch Klicken auf ein zweites Menü, während ein erstes geöffnet ist, das erste in der stopPropagation-Lösung geöffnet bleibt.
quelle
Das Ereignis hat eine Eigenschaft namens event.path des Elements, die eine "statisch geordnete Liste aller seiner Vorfahren in Baumreihenfolge" ist . Um zu überprüfen, ob ein Ereignis von einem bestimmten DOM-Element oder einem seiner untergeordneten Elemente stammt, überprüfen Sie einfach den Pfad für dieses bestimmte DOM-Element. Es kann auch verwendet werden, um mehrere Elemente zu überprüfen, indem
OR
die Elementprüfung in dersome
Funktion logisch ausgeführt wird .Also für Ihren Fall sollte es sein
quelle
event.path
ist keine Sache.Ich habe diese Methode in einem jQuery-Kalender-Plugin gefunden.
quelle
Hier ist die Vanille-JavaScript-Lösung für zukünftige Betrachter.
Wenn Sie beim Klicken auf ein Element im Dokument die ID des angeklickten Elements umschalten oder das ausgeblendete Element nicht ausgeblendet ist und das ausgeblendete Element das angeklickte Element nicht enthält, schalten Sie das Element um.
Code-Snippet anzeigen
Wenn Sie mehrere Schalter auf derselben Seite haben, können Sie Folgendes verwenden:
hidden
zum reduzierbaren Element hinzu.quelle
Ich bin überrascht, dass niemand das
focusout
Ereignis tatsächlich anerkannt hat:quelle
Wenn Sie Skripte für IE und FF 3 erstellen * und nur wissen möchten, ob der Klick in einem bestimmten Feldbereich aufgetreten ist, können Sie auch Folgendes verwenden:
quelle
Verwenden Sie stattdessen eine Flussunterbrechung, ein Unschärfe- / Fokusereignis oder eine andere knifflige Technik, um den Ereignisfluss einfach mit der Verwandtschaft des Elements abzugleichen:
Um den Klick außerhalb des Ereignis-Listeners zu entfernen, gehen Sie einfach wie folgt vor:
quelle
#menuscontainer
Sie immer noch durch die Eltern. Sie sollten dies zuerst überprüfen. Wenn es sich nicht um dieses Element handelt, gehen Sie in den DOM-Baum.if(!($(event.target).is("#menuscontainer") || $(event.target).parents().is("#menuscontainer"))){
. Es ist eine winzige Optimierung, die jedoch nur wenige Male in Ihrer Programmlebensdauer auftritt: für jeden Klick, wenn dasclick.menu-outside
Ereignis registriert ist. Es ist länger (+32 Zeichen) und verwendet keine MethodenverkettungVerwenden:
quelle
Wenn jemand hier neugierig ist, ist Javascript-Lösung (es6):
und es5, nur für den Fall:
});
quelle
Hier ist eine einfache Lösung durch reines Javascript. Es ist mit ES6 auf dem neuesten Stand :
quelle
() => {}
statt zu tunfunction() {}
. Was Sie dort haben, wird als einfaches JavaScript mit einem Twist von ES6 klassifiziert.Hängen Sie einen Klickereignis-Listener in das Dokument ein. Im Ereignis-Listener können Sie das Ereignisobjekt , insbesondere das event.target , anzeigen , um festzustellen, auf welches Element geklickt wurde:
quelle
Ich habe unten Skript verwendet und mit jQuery fertig.
Unten finden Sie den HTML-Code
Sie können das Tutorial hier lesen
quelle
Wenn Sie auf das Dokument klicken, blenden Sie ein bestimmtes Element aus, es sei denn, Sie klicken auf dasselbe Element.
quelle
Upvote für die beliebteste Antwort, aber hinzufügen
Ein Klick auf eine Bildlaufleiste [versteckt oder was auch immer] Ihr Zielelement nicht.
quelle
Für eine einfachere Verwendung und ausdrucksstärkeren Code habe ich ein jQuery-Plugin dafür erstellt:
Hinweis: Ziel ist das Element, auf das der Benutzer tatsächlich geklickt hat. Der Rückruf wird jedoch weiterhin im Kontext des ursprünglichen Elements ausgeführt, sodass Sie diesen wie erwartet in einem jQuery-Rückruf verwenden können.
Plugin:
Standardmäßig wird der Listener für Klickereignisse im Dokument platziert. Wenn Sie jedoch den Bereich des Ereignis-Listeners einschränken möchten, können Sie ein jQuery-Objekt übergeben, das ein übergeordnetes Element darstellt, das das oberste übergeordnete Element ist, bei dem Klicks abgehört werden. Dies verhindert unnötige Ereignis-Listener auf Dokumentebene. Offensichtlich funktioniert es nur, wenn das angegebene übergeordnete Element ein übergeordnetes Element Ihres ursprünglichen Elements ist.
Verwenden Sie wie folgt:
quelle