Mam pole wprowadzania, które wyświetla niestandardowe menu rozwijane. Chciałbym mieć następującą funkcjonalność:
- Gdy użytkownik kliknie gdziekolwiek poza polem wejściowym, menu powinno zostać usunięte.
- Jeśli, dokładniej, użytkownik kliknie element div w menu, menu powinno zostać usunięte i powinno nastąpić specjalne przetwarzanie w zależności od tego, który element div został kliknięty.
Oto moja realizacja:
Pole wejściowe ma onblur()
zdarzenie, które usuwa menu (ustawiając jego innerHTML
element nadrzędny na pusty ciąg), gdy użytkownik kliknie poza polem wejściowym. Elementy div w menu mają również onclick()
zdarzenia, które wykonują specjalne przetwarzanie.
Problem polega na tym, że onclick()
zdarzenia nigdy nie są uruchamiane po kliknięciu menu, ponieważ pole wejściowe onblur()
uruchamia się jako pierwsze i usuwa menu, w tym onclick()
s!
I rozwiązać problem dzielenia DIV menu onclick()
do onmousedown()
i onmouseup()
wydarzenia i ustawienie globalną flagę na myszy, która jest wydalana na mysz w górę, podobny do tego, co było sugerowane w tej odpowiedzi . Ponieważ onmousedown()
uruchamia się wcześniej onblur()
, flaga zostanie ustawiona, onblur()
jeśli kliknięto jeden z elementów div menu, ale nie, jeśli gdzieś indziej na ekranie. Jeśli menu zostało kliknięte, natychmiast wracam z niego onblur()
bez usuwania menu, a następnie czekam na onclick()
uruchomienie, po czym mogę bezpiecznie usunąć menu.
Czy jest bardziej eleganckie rozwiązanie?
Kod wygląda mniej więcej tak:
<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;
...
}
źródło
onmousedown
jest wykonywany przedonblur
testem w przeglądarce Firefox, Chrome i Internet Explorer.onMouseDown
zeevent.preventDefault()
ionClick
ze pożądanego działania.onClick
nie należy zastępowaćonMouseDown
.Chociaż to podejście w pewnym stopniu działa , są to zasadniczo różne zdarzenia, które mają różne oczekiwania w oczach użytkownika. W takim przypadku używanie
onMouseDown
zamiastonClick
zrujnuje przewidywalność oprogramowania. Zatem te dwa zdarzenia są niezamienne.Aby to zilustrować: po przypadkowym kliknięciu przycisku użytkownicy oczekują, że będą w stanie przytrzymać kliknięcie myszą, przeciągnąć kursor poza element i zwolnić przycisk myszy, co ostatecznie nie spowoduje żadnego działania.
onClick
robi to.onMouseDown
nie pozwala użytkownikowi na przytrzymanie przycisku myszy, a zamiast tego natychmiast wyzwoli akcję, bez żadnej możliwości dla użytkownika.onClick
to standard, według którego spodziewamy się wyzwalania działań na komputerze.W takiej sytuacji zadzwoń
event.preventDefault()
doonMouseDown
wydarzenia.onMouseDown
spowoduje domyślnie rozmycie i nie zrobi tego popreventDefault
wywołaniu. WtedyonClick
będzie miał szansę zadzwonić. Rozmycie będzie nadal miało miejsce, dopiero poonClick
.W końcu
onClick
zdarzenie jest połączeniemonMouseDown
ionMouseUp
, wtedy i tylko wtedy, gdy oba występują w tym samym elemencie.źródło
event.preventDefault()
zonMouseDown
wydarzenia, mojeonFocus
wydarzenie nie zostanie wywołaneWymienić na
onmousedown
zonfocus
. Więc to zdarzenie zostanie wyzwolone, gdy fokus znajdzie się wewnątrz pola tekstowego.Wymienić na
onmouseup
zonblur
. W chwili, gdy wyłączysz fokus z pola tekstowego, uruchomi się onblur.Myślę, że tego możesz potrzebować.
AKTUALIZACJA :
kiedy wykonujesz swoją funkcję onfocus -> usuń klasy, które zastosujesz w onblur i dodaj klasy, które chcesz wykonać onfocus
i
kiedy wykonujesz swoją funkcję onblur -> usuń klasy, które zastosujesz w onfocus i dodaj klasy, które chcesz wykonać onblur
Nie widzę potrzeby stosowania zmiennych flag.
AKTUALIZACJA 2:
Możesz używać wydarzeń onmouseout i onmouseover
onmouseover - Wykrywa, kiedy kursor jest nad nim.
onmouseout - Wykrywa, kiedy kursor wychodzi.
źródło
onmousedown()
ionmouseup()
w menu, a nie pola tekstowego / pola wprowadzania.Bardziej eleganckie (ale prawdopodobnie mniej wydajne) rozwiązanie:
Zamiast używać onblur wejścia do usuwania menu, użyj
document.onclick
, który uruchamia się poonblur
.Jednak oznacza to również, że menu jest usuwane po kliknięciu samego wejścia, co jest niepożądanym zachowaniem. Ustaw wartość
input.onclick
z,event.stopPropagation()
aby uniknąć propagowania kliknięć do zdarzenia kliknięcia dokumentu.źródło
zmienić onclick przez onfocus
nawet jeśli onblur i onclick nie układają się zbyt dobrze, ale oczywiście onfocus i tak onblur. ponieważ nawet po zamknięciu menu onfocus nadal obowiązuje dla elementu klikniętego w środku.
Zrobiłem i zadziałało.
źródło
Możesz użyć
setInterval
funkcji wewnątrz swojegoonBlur
handlera, na przykład:setInterval
funkcja usunie swojąonBlur
funkcję się od stosu wywołań, dodać bo ustawisz czas 0, ta funkcja zostanie wywołana po zakończeniu drugiej niezwłocznie obsługi zdarzeńźródło
setInterval
to zły pomysł, nigdy go nie anulujesz, więc będzie on stale uruchamiał twoją funkcję i najprawdopodobniej spowoduje, że Twoja witryna będzie używać maksymalnego procesora. UżyjsetTimeout
zamiast tego, jeśli zamierzasz używać tej techniki (której nie polecam). Uzależnienie aplikacji od czasu określonych zdarzeń jest ryzykowne.setTimeout
niesetInterval
), ale musiałem podbić je do250
ms, zanim synchronizacja nastąpi we właściwej kolejności. Ten błąd prawdopodobnie nadal będzie istniał na wolniejszych urządzeniach, a także powoduje, że opóźnienie jest zauważalne. WypróbowałemonMouseDown
i działa dobrze. Zastanawiam się, czy potrzebuje również wydarzeń dotykowych.