У меня есть поле ввода, которое вызывает настраиваемое раскрывающееся меню. Хотелось бы следующего функционала:
- Когда пользователь щелкает где-нибудь за пределами поля ввода, меню должно быть удалено.
- Если, более конкретно, пользователь щелкает div внутри меню, меню должно быть удалено, и должна происходить специальная обработка в зависимости от того, какой div был нажат.
Вот моя реализация:
Поле ввода имеет onblur()
событие, которое удаляет меню (путем установки его родительского элемента innerHTML
на пустую строку) всякий раз, когда пользователь щелкает мышью за пределами поля ввода. Дивы внутри меню также имеют onclick()
события, которые выполняют специальную обработку.
Проблема в том, что onclick()
события никогда не срабатывают при нажатии на меню, потому что поле ввода onblur()
срабатывает первым и удаляет меню, включая onclick()
s!
Я решил эту проблему путем разделения дивы меню onclick()
в onmousedown()
и onmouseup()
события и установив глобальный флаг вниз мыши , который очищается от мыши вверх, подобно тому , что было предложено в этом ответе . Поскольку onmousedown()
срабатывает раньше onblur()
, флаг будет установлен, onblur()
если был нажат один из разделов меню, но не если где-то еще на экране. Если меню было нажато, я немедленно выхожу из него, onblur()
не удаляя меню, затем жду, пока сработает кнопка, после onclick()
чего я могу безопасно удалить меню.
Есть ли более элегантное решение?
Код выглядит примерно так:
<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;
...
}
источник
onmousedown
выполняется передonblur
тестированием в Firefox, Chrome и Internet Explorer.onMouseDown
сevent.preventDefault()
иonClick
с нужным действием.onClick
не следует заменять наonMouseDown
.Хотя этот подход в некоторой степени работает , это два принципиально разных события, которые имеют разные ожидания в глазах пользователя. Использование
onMouseDown
вместоonClick
разрушит предсказуемость вашего программного обеспечения в этом случае. Таким образом, эти два события не взаимозаменяемы.Для иллюстрации: при случайном нажатии кнопки пользователи ожидают, что смогут удерживать щелчок мыши, перетащить курсор за пределы элемента и отпустить кнопку мыши, что в конечном итоге приведет к отсутствию действий.
onClick
Является ли это.onMouseDown
не позволяет пользователю удерживать мышь, а вместо этого немедленно запускает действие, не обращаясь за помощью к пользователю.onClick
стандарт, по которому мы ожидаем запускать действия на компьютере.В этой ситуации звоните
event.preventDefault()
наonMouseDown
мероприятие.onMouseDown
по умолчанию вызовет событие размытия и не будет делать этого приpreventDefault
вызове. ТогдаonClick
будет шанс , что вас позвонят. Событие размытия все равно произойдет, только послеonClick
.В конце концов,
onClick
событие представляет собой комбинациюonMouseDown
иonMouseUp
, если и только если они оба происходят в одном элементе.источник
event.preventDefault()
наonMouseDown
мероприятии, моеonFocus
мероприятие не называетсяЗаменить на
onmousedown
сonfocus
. Таким образом, это событие будет запускаться, когда фокус находится внутри текстового поля.Заменить на
onmouseup
сonblur
. В тот момент, когда вы уберете фокус с текстового поля, запустится onblur.Думаю, это то, что вам может понадобиться.
ОБНОВЛЕНИЕ :
когда вы выполняете свою функцию onfocus -> удалите классы, которые вы будете применять в onblur, и добавьте классы, которые вы хотите выполнить, onfocus
и
когда вы выполняете свою функцию onblur -> удалите классы, которые вы будете применять в onfocus, и добавьте классы, которые вы хотите выполнить onblur
Я не вижу необходимости во флаговых переменных.
ОБНОВЛЕНИЕ 2:
Вы можете использовать события onmouseout и onmouseover
onmouseover - обнаруживает, когда курсор находится над ним.
onmouseout - обнаруживает, когда курсор уходит.
источник
onmousedown()
иonmouseup()
в меню, а не в текстовом поле / поле ввода.Более элегантное (но, вероятно, менее производительное) решение:
Вместо использования onblur ввода для удаления меню используйте
document.onclick
, которое срабатывает послеonblur
.Однако это также означает, что меню удаляется при нажатии на сам вход, что является нежелательным поведением. Установите
input.onclick
с,event.stopPropagation()
чтобы избежать распространения щелчков на событие щелчка документа.источник
изменить onclick на onfocus
даже если onblur и onclick не очень хорошо уживаются, но, очевидно, onfocus и да, onblur. поскольку даже после того, как меню закрыто, onfocus по-прежнему действует для элемента, внутри которого щелкнули.
Я сделал, и это сработало.
источник
Вы можете использовать
setInterval
функцию внутри своегоonBlur
обработчика, например:setInterval
функция удалитьonBlur
функцию из стека вызовов, добавить , потому что вы установите время на 0, эта функция будет вызвана сразу же после того, как другой обработчик события закончилисточник
setInterval
- плохая идея, вы никогда не отменяете ее, поэтому она будет постоянно запускать вашу функцию и, скорее всего, заставит ваш сайт использовать максимальное количество ЦП. ИспользуйтеsetTimeout
вместо этого, если собираетесь использовать эту технику (которую я не рекомендую). Заставлять ваше приложение зависеть от времени определенных событий - рискованное дело.setTimeout
нетsetInterval
), но мне пришлось увеличить его до250
мс, прежде чем время произойдет в правильном порядке. Эта ошибка, вероятно, все еще будет существовать на более медленных устройствах, а также делает задержку заметной. Я попробовал,onMouseDown
и он отлично работает. Интересно, нужны ли ему и события касания.