У меня есть несколько HTML-меню, которые я показываю полностью, когда пользователь нажимает на заголовок этих меню. Я хотел бы скрыть эти элементы, когда пользователь щелкает за пределами области меню.
Возможно ли что-то подобное с jQuery?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
javascript
jquery
click
Sergio del Amo
источник
источник
event.target
и безevent.stopPropagation
.Ответы:
Прикрепите событие щелчка к телу документа, которое закрывает окно. Прикрепите отдельное событие щелчка к контейнеру, который останавливает распространение в теле документа.
источник
$('html').click()
не тело. Тело всегда имеет высоту своего содержания. Если контента не так много или экран очень высокий, он работает только на части, заполненной телом.Вы можете прослушать событие click,
document
а затем убедиться, что#menucontainer
он не является предком или целью выбранного элемента с помощью.closest()
.Если это не так, то выбранный элемент находится за пределами,
#menucontainer
и его можно смело скрывать.Редактировать - 2017-06-23
Вы также можете очистить после прослушивателя событий, если вы планируете закрыть меню и хотите прекратить прослушивание событий. Эта функция будет очищать только недавно созданного слушателя, сохраняя любые другие слушатели щелчка
document
. С синтаксисом ES2015:Редактировать - 2018-03-11
Для тех, кто не хочет использовать jQuery. Вот приведенный выше код на простом vanillaJS (ECMAScript6).
ПРИМЕЧАНИЕ: это основано на комментарии Алекса, чтобы просто использовать
!element.contains(event.target)
вместо части jQuery.Но
element.closest()
теперь он также доступен во всех основных браузерах (версия W3C немного отличается от версии jQuery). Полифилы можно найти здесь: Element.closest ()Изменить - 2020-05-21
В том случае, если вы хотите, чтобы пользователь мог щелкать и перетаскивать элемент, затем отпустите кнопку мыши вне элемента, не закрывая элемент:
И в
outsideClickListener
:источник
!element.contains(event.target)
с использованием Node.contains ()Причина того, что этот вопрос так популярен и имеет так много ответов, заключается в том, что он обманчиво сложен. После почти восьми лет и десятков ответов я искренне удивлен, увидев, как мало внимания уделяется доступности.
Это благородное дело и актуальная проблема. Название вопроса, на которое, как представляется, пытается ответить большинство ответов, содержится неудачная красная сельдь.
Подсказка: это слово «клик» !
Вы на самом деле не хотите связывать обработчики кликов.
Если вы связываете обработчики кликов, чтобы закрыть диалоговое окно, вы уже потерпели неудачу. Причина, по которой вы потерпели неудачу, заключается в том, что не все запускают
click
события. Пользователи, не использующие мышь, смогут выйти из вашего диалога (а ваше всплывающее меню, возможно, является типом диалога), нажав Tab, и тогда они не смогут читать содержимое, находящееся за диалоговым окном, без последующего запускаclick
события.Итак, давайте перефразируем вопрос.
Это цель. К сожалению, теперь нам нужно связать
userisfinishedwiththedialog
событие, и это связывание не так просто.Итак, как мы можем определить, что пользователь закончил использовать диалог?
focusout
событиеХорошее начало - определить, покинул ли фокус диалог.
Подсказка: будьте осторожны с
blur
событием,blur
не распространяется, если событие было связано с фазой барботирования!JQuery's
focusout
будет хорошо. Если вы не можете использовать jQuery, то вы можете использоватьblur
на этапе захвата:Кроме того, для многих диалогов вам нужно позволить контейнеру получить фокус. Добавьте,
tabindex="-1"
чтобы диалоговое окно получало фокус динамически, не прерывая процесс табуляции.Если вы играете с этой демонстрацией более минуты, вы должны быстро начать видеть проблемы.
Во-первых, ссылка в диалоговом окне не активна. Попытка щелкнуть по нему или открыть вкладку приведет к закрытию диалога до того, как произойдет взаимодействие. Это связано с тем, что фокусировка внутреннего элемента инициирует
focusout
событие, прежде чемfocusin
снова вызвать событие.Исправление состоит в том, чтобы поставить в очередь изменение состояния в цикле событий. Это можно сделать с помощью
setImmediate(...)
илиsetTimeout(..., 0)
для браузеров, которые не поддерживаютsetImmediate
. После постановки в очередь его можно отменить следующимfocusin
:Показать фрагмент кода
Вторая проблема заключается в том, что диалоговое окно не закрывается при повторном нажатии ссылки. Это связано с тем, что диалоговое окно теряет фокус, вызывая поведение закрытия, после чего щелчок по ссылке запускает диалоговое окно для повторного открытия.
Как и в предыдущем выпуске, необходимо управлять состоянием фокуса. Учитывая, что изменение состояния уже поставлено в очередь, это просто вопрос обработки событий фокуса на триггерах диалога:
Это должно выглядеть знакомоПоказать фрагмент кода
Esc ключ
Если вы думали, что справились с состояниями фокуса, вы можете сделать еще больше, чтобы упростить работу с пользователем.
Это часто «приятно иметь» функцию, но обычно когда у вас есть модальное или всплывающее окно любого рода, Escключ закрывает его.
Показать фрагмент кода
Если вы знаете, что в диалоге есть фокусируемые элементы, вам не нужно фокусировать диалог напрямую. Если вы создаете меню, вы можете вместо этого сфокусировать первый пункт меню.
Показать фрагмент кода
Поддержка ролей WAI-ARIA и других специальных возможностей
Надеемся, что этот ответ охватывает основы доступной поддержки клавиатуры и мыши для этой функции, но, поскольку он уже довольно значительный, я собираюсь избегать любого обсуждения ролей и атрибутов WAI-ARIA , однако я настоятельно рекомендую разработчикам обратиться к спецификации для получения подробной информации на какие роли они должны использовать и любые другие соответствующие атрибуты.
источник
Другие решения здесь не работают для меня, поэтому мне пришлось использовать:
источник
&& !$(event.target).parents("#foo").is("#foo")
внутриIF
оператора, чтобы любые дочерние элементы не закрывали меню при нажатии..is('#foo, #foo *')
, но я не рекомендую связывать обработчики щелчков для решения этой проблемы .!$(event.target).closest("#foo").length
было бы лучше и избавляет от необходимости добавления @ honyovk.У меня есть приложение, которое работает аналогично примеру Эрана, за исключением того, что я прикрепляю событие click к телу при открытии меню ... Вроде как:
Больше информации о функции jQuery
one()
источник
.one
- внутри$('html')
обработчика - напишите a$('html').off('click')
.one
Обработчик будет автоматически вызыватьoff
(как это показано в документации JQuery).После исследования я нашел три рабочих решения (я забыл ссылки на страницы для справки)
Первое решение
Второе решение
Третье решение
источник
document.getElementsByClassName
, если кто-то знает, пожалуйста, поделитесь.У меня работает просто отлично.
источник
#menucontainer
вопроса, было о щелчкеtabindex="-1"
к ,#menuscontainer
чтобы заставить его работать. Кажется, что если вы поместите тег ввода в контейнер и нажмете на него, контейнер будет скрыт.Теперь для этого есть плагин: внешние события ( запись в блоге )
Следующее происходит, когда обработчик clickoutside (WLOG) привязан к элементу:
Таким образом, никакие события не останавливаются от распространения, и дополнительные обработчики кликов могут использоваться «над» элементом с внешним обработчиком.
источник
$( '#element' ).on( 'clickoutside', function( e ) { .. } );
Это сработало для меня отлично!
источник
Я не думаю, что вам действительно нужно закрывать меню, когда пользователь нажимает снаружи; вам нужно, чтобы меню закрывалось, когда пользователь вообще щелкает в любом месте страницы. Если вы нажмете на меню, или от меню оно должно закрыться правильно?
Не найдя удовлетворительных ответов выше, я попросил написать этот пост на днях. Для более педантичных есть ряд замечаний:
body { margin-left:auto; margin-right: auto; width:960px;}
источник
Как сказал другой автор, есть много ошибок, особенно если отображаемый элемент (в данном случае меню) имеет интерактивные элементы. Я нашел следующий метод достаточно надежным:
источник
Простое решение для ситуации:
Приведенный выше скрипт будет скрывать,
div
если внеdiv
нажатия кнопки вызывается событие.Вы можете увидеть следующий блог для получения дополнительной информации: http://www.codecanal.com/detect-click-outside-div-using-javascript/
источник
Solution1
Вместо использования event.stopPropagation (), который может иметь побочные эффекты, просто определите простую переменную-флаг и добавьте одно
if
условие. Я проверил это и работал должным образом без каких-либо побочных эффектов stopPropagation:Solution2
С простым
if
условием:источник
Проверьте цель события щелчка окна (она должна распространяться на окно, если она не захвачена где-либо еще), и убедитесь, что это не какой-либо из элементов меню. Если это не так, то вы находитесь за пределами вашего меню.
Или проверьте положение щелчка и посмотрите, содержится ли оно в области меню.
источник
У меня был успех с чем-то вроде этого:
Логика такова: когда
#menuscontainer
отображается, привязать обработчик щелчка к телу, которое скрывается,#menuscontainer
только если цель (щелчка) не является его дочерней.источник
Как вариант:
Он не имеет проблем с остановкой распространения событий и лучше поддерживает несколько меню на одной странице, где нажатие на второе меню, когда открыто первое, оставляет первое открытие в решении stopPropagation.
источник
Событие имеет свойство с именем event.path элемента, которое представляет собой «статический упорядоченный список всех его предков в древовидной структуре» . Чтобы проверить, произошло ли событие из определенного элемента DOM или одного из его дочерних элементов, просто проверьте путь для этого конкретного элемента DOM. Его также можно использовать для проверки нескольких элементов, логически
OR
проверяя элемент вsome
функции.Так что для вашего случая это должно быть
источник
event.path
это не вещь.Я нашел этот метод в некотором плагине календаря jQuery.
источник
Вот ванильное решение JavaScript для будущих зрителей.
Если щелкнуть любой элемент в документе, если идентификатор выбранного элемента переключен или скрытый элемент не скрыт, а скрытый элемент не содержит выбранный элемент, переключите элемент.
Показать фрагмент кода
Если у вас будет несколько переключателей на одной странице, вы можете использовать что-то вроде этого:
hidden
к складному элементу.источник
Я удивлен, что никто на самом деле не признал
focusout
событие:источник
Если вы пишете сценарии для IE и FF 3. * и хотите просто знать, произошел ли щелчок в определенной области окна, вы также можете использовать что-то вроде:
источник
Вместо этого используйте прерывание потока, событие размытия / фокуса или любую другую хитрую технику, просто сопоставьте поток событий с родством элемента:
Чтобы удалить щелчок вне слушателя события, просто:
источник
#menuscontainer
вы все еще переживаете его родителей. Вы должны сначала проверить это, и если это не тот элемент, тогда поднимитесь по дереву DOM.if(!($(event.target).is("#menuscontainer") || $(event.target).parents().is("#menuscontainer"))){
. Это крошечная оптимизация, но она происходит всего несколько раз за время жизни вашей программы: для каждого клика, еслиclick.menu-outside
событие зарегистрировано. Это длиннее (+32 символа) и не использует цепочку методовИспользование:
источник
Если кому-то интересно, вот решение javascript (es6):
и es5, на всякий случай:
});
источник
Вот простое решение с помощью чистого JavaScript. Это актуально с ES6 :
источник
() => {}
вместо ES6 делается единственное, что актуально для ES6function() {}
. То, что у вас есть, классифицируется как простой JavaScript с изюминкой ES6.Подцепите слушателя события щелчка на документе. Внутри слушателя событий вы можете посмотреть на объект события , в частности, на event.target, чтобы увидеть, какой элемент был нажат:
источник
Я использовал скрипт ниже и сделал с JQuery.
Ниже найдите код HTML
Вы можете прочитать учебник здесь
источник
Если вы щелкнете по документу, скройте заданный элемент, если только вы не нажмете на этот же элемент.
источник
Upvote для самого популярного ответа, но добавить
Итак, щелчок на полосе прокрутки не [скрывает или что-то еще] ваш целевой элемент.
источник
Для более легкого использования и более выразительного кода я создал для этого плагин jQuery:
Примечание: цель - это элемент, на который пользователь фактически нажал. Но обратный вызов по-прежнему выполняется в контексте исходного элемента, поэтому вы можете использовать его, как и следовало ожидать в обратном вызове jQuery.
Плагин:
По умолчанию прослушиватель событий щелчка помещается в документ. Однако, если вы хотите ограничить область прослушивания событий, вы можете передать объект jQuery, представляющий родительский элемент уровня, который будет верхним родителем, на котором будут прослушиваться щелчки. Это предотвращает ненужные прослушиватели событий уровня документа. Очевидно, что это не будет работать, если предоставленный родительский элемент не является родителем вашего исходного элемента.
Используйте так:
источник