Ich habe ein Eingabefeld, das ein benutzerdefiniertes Dropdown-Menü aufruft. Ich möchte die folgende Funktionalität:
- Wenn der Benutzer irgendwo außerhalb des Eingabefelds klickt, sollte das Menü entfernt werden.
- Wenn der Benutzer im Menü auf ein Div klickt, sollte das Menü entfernt werden, und es sollte eine spezielle Verarbeitung erfolgen, die darauf basiert, auf welches Div geklickt wurde.
Hier ist meine Implementierung:
Das Eingabefeld enthält ein onblur()
Ereignis, das das Menü löscht (indem die übergeordneten Elemente innerHTML
auf eine leere Zeichenfolge gesetzt werden), wenn der Benutzer außerhalb des Eingabefelds klickt. Die Divs im Menü haben auch onclick()
Ereignisse, die die spezielle Verarbeitung ausführen.
Das Problem ist, dass die onclick()
Ereignisse niemals ausgelöst werden, wenn auf das Menü geklickt wird, da das Eingabefeld onblur()
zuerst ausgelöst wird und das Menü einschließlich des onclick()
s!
Ich habe das Problem gelöst, indem ich die Menü-Divs onclick()
in onmousedown()
und onmouseup()
Ereignisse aufgeteilt und ein globales Flag bei gedrückter Maus gesetzt habe, das mit der Maus nach oben gelöscht wird, ähnlich wie in dieser Antwort vorgeschlagen . Da onmousedown()
zuvor ausgelöst wurde onblur()
, wird das Flag gesetzt, onblur()
wenn auf eines der Menü-Divs geklickt wurde, nicht jedoch, wenn es sich an einer anderen Stelle auf dem Bildschirm befand. Wenn auf das Menü geklickt wurde, kehre ich sofort zurück, onblur()
ohne das Menü zu löschen, und warte dann, onclick()
bis das Menü ausgelöst wird. An diesem Punkt kann ich das Menü sicher löschen.
Gibt es eine elegantere Lösung?
Der Code sieht ungefähr so aus:
<div class="menu" onmousedown="setFlag()" onmouseup="doProcessing()">...</div>
<input id="input" onblur="removeMenu()" ... />
var mouseflag;
function setFlag() {
mouseflag = true;
}
function removeMenu() {
if (!mouseflag) {
document.getElementById('menu').innerHTML = '';
}
}
function doProcessing(id, name) {
mouseflag = false;
...
}
quelle
onmousedown
es vor demonblur
Testen in Firefox, Chrome und Internet Explorer ausgeführt.onMouseDown
mitevent.preventDefault()
undonClick
mit Ihrer gewünschten Aktion.onClick
sollte nicht durch ersetzt werdenonMouseDown
.Während dieser Ansatz etwas funktioniert , handelt es sich bei den beiden Ereignissen um grundlegend unterschiedliche Ereignisse, die in den Augen des Benutzers unterschiedliche Erwartungen haben. Die Verwendung von
onMouseDown
anstelle vononClick
wird in diesem Fall die Vorhersehbarkeit Ihrer Software beeinträchtigen. Somit sind die beiden Ereignisse nicht austauschbar.Zur Veranschaulichung: Wenn Benutzer versehentlich auf eine Schaltfläche klicken, können sie den Mausklick gedrückt halten, den Cursor außerhalb des Elements ziehen und die Maustaste loslassen, was letztendlich zu keiner Aktion führt.
onClick
macht dies.onMouseDown
Der Benutzer kann die Maus nicht gedrückt halten und löst stattdessen sofort eine Aktion aus, ohne dass der Benutzer darauf zurückgreifen muss.onClick
ist der Standard, nach dem wir erwarten, Aktionen auf einem Computer auszulösen.Rufen Sie in dieser Situation
event.preventDefault()
dieonMouseDown
Veranstaltung auf.onMouseDown
verursacht standardmäßig ein Unschärfeereignis und tut dies nicht, wennpreventDefault
es aufgerufen wird. DannonClick
haben Sie die Chance, angerufen zu werden. Ein Unschärfeereignis wird immer noch auftreten, erst danachonClick
.Schließlich ist das
onClick
Ereignis eine Kombination ausonMouseDown
undonMouseUp
, wenn und nur wenn beide innerhalb desselben Elements auftreten.quelle
event.preventDefault()
einonMouseDown
Ereignis verwende, wird meinonFocus
Ereignis nicht aufgerufenErsetzen
onmousedown
durchonfocus
. Dieses Ereignis wird also ausgelöst, wenn sich der Fokus innerhalb des Textfelds befindet.Ersetzen
onmouseup
durchonblur
. Sobald Sie Ihren Fokus aus dem Textfeld entfernen, wird onblur ausgeführt.Ich denke, das ist es, was du vielleicht brauchst.
UPDATE :
Wenn Sie Ihre Funktion onfocus ausführen -> entfernen Sie die Klassen, die Sie in onblur anwenden möchten, und fügen Sie die Klassen hinzu, die onfocus ausgeführt werden sollen
und
Wenn Sie Ihre Funktion onblur ausführen -> entfernen Sie die Klassen, die Sie in onfocus anwenden möchten, und fügen Sie die Klassen hinzu, die onblur ausgeführt werden sollen
Ich sehe keine Notwendigkeit für Flag-Variablen.
UPDATE 2:
Sie können die Ereignisse onmouseout und onmouseover verwenden
onmouseover - Erkennt, wenn sich der Cursor darüber befindet.
onmouseout - Erkennt, wann der Cursor geht.
quelle
onmousedown()
undonmouseup()
im Menü nicht das Textfeld / Eingabefeld.Eine elegantere (aber wahrscheinlich weniger performante) Lösung:
Anstatt die Onblur der Eingabe zu verwenden, um das Menü zu entfernen, verwenden Sie
document.onclick
, was danach ausgelöst wirdonblur
.Dies bedeutet jedoch auch, dass das Menü entfernt wird, wenn auf die Eingabe selbst geklickt wird. Dies ist ein unerwünschtes Verhalten. Setzen Sie ein
input.onclick
mitevent.stopPropagation()
, um zu vermeiden, dass Klicks auf das Dokumentklickereignis übertragen werden.quelle
Ändern Sie onclick durch onfocus
auch wenn onblur und onclick nicht sehr gut miteinander auskommen, aber offensichtlich onfocus und ja onblur. da auch nach dem Schließen des Menüs der Onfocus für das darin angeklickte Element weiterhin gültig ist.
Ich habe es getan und es hat funktioniert.
quelle
Sie können eine
setInterval
Funktion in IhremonBlur
Handler wie folgt verwenden:Die
setInterval
Funktion entfernt IhreonBlur
Funktion aus dem Aufrufstapel. Fügen Sie hinzu, da Sie die Zeit auf 0 gesetzt haben. Diese Funktion wird sofort aufgerufen, nachdem ein anderer Ereignishandler beendet wurdequelle
setInterval
ist eine schlechte Idee, Sie brechen es nie ab, so dass es Ihre Funktion kontinuierlich ausführt und höchstwahrscheinlich dazu führt, dass Ihre Site die maximale CPU verwendet. Verwenden SiesetTimeout
stattdessen, wenn Sie diese Technik verwenden möchten (was ich nicht empfehle). Es ist ein riskantes Geschäft, Ihre App vom Zeitpunkt bestimmter Ereignisse abhängig zu machen.setTimeout
nichtsetInterval
), aber ich musste sie auf250
ms erhöhen, bevor das Timing in der richtigen Reihenfolge erfolgt. Dieser Fehler wird wahrscheinlich auch auf langsameren Geräten bestehen bleiben und macht die Verzögerung spürbar. Ich habe es versuchtonMouseDown
und es funktioniert gut. Ich frage mich, ob es auch die Touch-Events braucht.