jQuery: Закрытие элемента по клику за пределами его области (вне элемента)

Когда бывает нужно скрыть (закрыть) элемент по клику за его пределами? Первое, что мне приходит в голову, это всплывающие (popup) окна и выпадающие (dropdown) меню. Понятное дело, что применение может быть гораздо шире.

Согласитесь, что намного удобнее закрыть всплывающее окно, кликнув за его пределами, чем тащить указатель мыши к крестику и кликать по нему. А в некоторых ситуациях крестик и вовсе использовать не удастся (выпадающие кастомные селекты или меню).

И да, как только люди с этим не шаманят! Решений в интернете полно, но оптимальными их не назовёшь. Самое часто встречающееся из них, это когда скрипт проверяет, находится ли указатель мыши над элементом или нет.

Ну вот зачем усложнять код?

Хотя на самом деле ответ действительно очевиден — разработчики не знают, что можно сделать правильнее и проще, и делают так, как могут. Давайте разберем алгоритм:

  1. У нас открыто всплывающее окно, меню или что-то ещё.
  2. Нам нужно, чтобы оно закрывалось не только на крестик (если таковой вообще имеется), но и по клику где-нибудь за его границами.
  3. Значит нам нужно событие «Когда произошёл клик по странице».
  4. В событие нужно добавить два условия «Если клик был не по нашему элементу» и «Если клик был не по дочерним элементам нашего элемента».
  5. Если оба условия выполняются, скрываем элемент.

Проще простого, код jQuery будет таким:

jQuery(function($){
	$(document).mouseup(function (e){ // событие клика по веб-документу
		var div = $("#popup"); // тут указываем ID элемента
		if (!div.is(e.target) // если клик был не по нашему блоку
		    && div.has(e.target).length === 0) { // и не по его дочерним элементам
			div.hide(); // скрываем его
		}
	});
});
Всплывающее окно на jQuery

Для данного примера можно ещё добавить событие onclick, чтобы окно также закрывалось при клике на крестик.

Подпишитесь, чтобы раз в неделю получать свежие статьи с блога по email.

Смотрите также

Комментарии 18

  • Илья2 января 2015 в 13:01 #

    Вот вопрос - а надо ли проверять дочерние элементы, если событие всё равно поднимается по дереву DOM вверх? Я как-то делал без проверки, и работало.

  • Алексей14 мая 2015 в 09:05 #

    Коротко и ясно. Спасибо!

  • Алексей15 сентября 2015 в 11:09 #

    // тут указываем ID элемента
    тут не только id можно указывать, но и класс элемента.

    Спасибо за статью, время сберегла! Очень толково и сразу все заработало.

  • Stepan10 октября 2015 в 20:10 #

    Спасибо большое за решение! Полдня потратил почти, ничего вразумительного не нашёл)) А тут ваша статья!

  • j4d10 октября 2015 в 20:10 #

    Спасибо! Отличное решение.

  • Maxim19 октября 2015 в 17:10 #

    Супер! Спасибо большое все работает! Подскажите стоит писать проверку если popup закрыт? чтобы скрипт срабатывал не каждый раз когда я нажимаю не важно где!

  • Александр9 ноября 2015 в 13:11 #

    Есть такой вопрос. Сам попап больших размеров высоту, я сделал так, что при открытие попапа скрол у боди исчезает, появляется попап с маской, у которой как раз скрол и появляется, но проблема в том, что при событие клика работает и на сам скрол, т.е при зажатие ползунка и перетягивании его и отпускании закрывается весь попап. Как избежать подобной ситуации? Спасибо.

    • Миша9 ноября 2015 в 16:11 #

      Предыдущий ответ на ваш комментарий выглядел как спам..

      Значит у попапа должен быть скролл?
      Я рекомендую сам попап запихнуть в ещё один блок div и именно на этот div, который без скролла и повесить событие.

      • Александр9 ноября 2015 в 17:11 #

        Я не совсем корректно выразился. Так и есть, попап лежит в диве, который при своем появлении имеет посишн фиксед, скрипт в этот момент убирает скрол у всего боди. В этом диве и лежит попап, который посишн релатив, и добавлен скрол авто диву, тем самым появляется скрол с боку страницы, только в случае, если поап больше высоты экрана. Вопрос заключается в следующем, как избежать срабатывания события клика по самому скролу и данного дива? Точнее выходит такЖ появляется попап, он больше высоты монитора, я могу его прокрутить колесом мышки либо же зажать позунок и тянуть вверх(вниз), но после отпускания ползунка сработает срипт на закрытие всего попапа. Скрол находится у родительского элемента попапа. Спасибо.

  • Евгений Кириллов30 июня 2016 в 00:06 #

    на iPhone не сработало :(

    Сделал так:
    label - фоновый фиксированный блок 100% высоты и ширины с затемнением :)
    input type="checkbox" - скрыт, через состояние выбран/не выбран влияем на отображение последующих блоков через css

    input[id="fon-inp"]:checked ~ .fon {
       display: none;
    }

Оставить комментарий / вопрос

phpjsHTMLCSSSQLПросто код
  Для того, чтобы оставить комментарий, пожалуйста, зарегистрируйтесь или авторизуйтесь на сайте.
Получайте новости блога по email или следите за мной в социальных сетях.
  • Владимир: и на третьей строке не хватает скобки ) закрывающей if :)

  • Миша: Добрый вечер! Рекомендую получить ID пользователя через функцию get_current_user_id().

  • Дмитрий: Миша, подскажите пожалуйста, я использую такой редирект, но он не срабатывает: add_action( 'template_redirect', funct...

  • Миша: Ну как не определена - это аргумент функции. Или я просто вас не до конца понимаю.

  • Артем: Ага, понял. Вот только почему $args? Она же нигде не определена, по логике должна быть переменная $true_field_params или...