Javascript → Как скрыть элемент при клике вне этого элемента

25.10.2011

Распространённая задача — скрыть всплывающее js окно при клике вне этого окна.

Смысл в следующем — вешаем на документ обработчик onclick, который благодаря всплытию событий (bubbling) будет ловить все клики на странице. В этом обработчике, в переменной event.target будет доступен элемент, на котором произошёл клик. С помощью jQuery метода closest() проверяем где произошёл клик — на элементе или вне элемента. Если вне, то скрываем элемент.

HTML:

<a href="#" id="toggle-link">Show message</a>
<div id="message">
    <p>Some text.</p>
</div>

Javascript:

$('#toggle-link').click(function(e) {
    var $message = $('#message');
    
    if ($message.css('display') != 'block') {
        $message.show();
        
        var firstClick = true;
        $(document).bind('click.myEvent', function(e) {
            if (!firstClick && $(e.target).closest('#message').length == 0) {
                $message.hide();
                $(document).unbind('click.myEvent');
            }
            firstClick = false;
        });
    }
    
    e.preventDefault();
});

Пример работы.

Переменная firstClick нужна, чтобы не скрывать #message сразу после его показа, так как bind() сработает до всплытия события.

Метод e.preventDefault(); запрещает выполнять дефолтную реакцию ссылки на клик, т.е. переход на пустой анкор #.

Добавлено 09.06.2014

Способ 2:

$(function() {
    $('#toggle-link').click(function(event) {
        $('#message').toggle();
    });
    $(document).click(function (event) {
        if ($(event.target).closest('#message').length == 0 && $(event.target).attr('id') != 'toggle-link') {
            $('#message').hide();
        }
    });
});
Похожие записи

Комментарии

Спасибо, действительно интересное и полезное решение. Есть еще вариант обернуть

$(document).bind(...);

в show() с duration=1, правда получается не очень красиво, зато меньше на две строчки. http://jsfiddle.net/p4kEm/10/

Гость
02.11.2011, 16:16

Конечно я навлеку тысячи ненависти сейчас. Но, что делать, если jquery старый? Ибо closest() появился только в 1.3.
А у друпала 6 по умолчанию, 1.2.6, если не ошибаюсь, в общем ниже версия.
Как такую задачу выполнить без оверлея прозрачного?

Кстати, недавно такую же задачу решал:

$('#open-login-link').click(function(e) {
    $('#user-login-form').toggle()
    e.preventDefault()
    e.stopPropagation()
  })
$('#user-login-form').click(function(e)  {e.stopPropagation()})
$('body').click(function() {$('#user-login-form').hide()})

тут есть пару проблем:

1. не сработает если всплывающих окон будет больше одного
2. дёргать .hide() на каждый клик в браузере имхо не разумно

Про hide() да, стоит переделать, хотя думаю, конечный пользователь все равно разницы не ощутит. В любом случае использование stopPropagation(), упрощает код.

Кстати, всесто $message.css('display') != 'block' можно сделать так $message.is(':hidden')

Насколько глупо вместо e.preventDefault() использовать return false? Я всегда так делаю.

return false запрещает всплытие, что не всегда уместно

Петров Николай
20.01.2012, 05:22

Отличная работа!

Если поставить return false вместо e.preventDefault();
- приходится два раза кликать вне попапа, чтобы он закрылся

В скрипте все круто, только я принципиально не работаю со стилями напрямую из JS, предпочитая оперировать только классами. Объяснять долго, но это дает более высокую степень свободы для разметки. Да, в данном случае эта свобода не нужна, но у меня это уже привычка.

Сделал так

$('.langSelectLink').click(function(e) {
	var popup = $('.linkSelectPopup');

	if (popup.hasClass('langSelectionHidden')) {
		popup.removeClass('langSelectionHidden');
		
		var firstClick = true;
		$(document).bind('click.myEvent', function(e) {
			if (!firstClick && $(e.target).closest('.linkSelectPopup').length == 0) {
				popup.addClass('langSelectionHidden');
				$(document).unbind('click.myEvent');
			}
			firstClick = false;
		});
	}

	e.preventDefault();
});

Ну и стиль

.langSelectionHidden {
	display:none !important;
}
Странник
08.11.2012, 12:52

Примного Вам благодарен, данный пример меня выручил.

Александр
09.09.2013, 17:21

а как быть если каких блоков не один?(Например: несколько блоков идут подряд, при клике на которые должны появляться внутренние блоки. И когда ты щелкаешь на блок, то внутренний блок скрывается) Данный метод не работает если щелкать подряд меду этими блоками(внутренние блоки перестают закрываться).

Спасибо за прекрасный пример!

Все работает отлично, но на одной из страниц конфликтует со слайдером (jflowSlider), т.е. элемент скрывается при автоматическом изменении слайдов.

Буду искренне благодарен за любую помощь в решении моей проблемы!

Алексей
28.09.2014, 12:45

Подскажите пожалуйста, как сделать тут так, чтобы при нажатии, появлялся блок с информацией, но скрывалась ссылка по которой кликали и вместо этого появилась ссылка в самом блоке, типа - (скрыть) ??? Спасибо!!! Если можно, то пропишите полностью скрипт так я в скриптах не понимаю....

Андрей
24.10.2014, 08:44

а как быть если каких блоков не один?(Например: несколько блоков идут подряд, при клике на которые должны появляться внутренние блоки. И когда ты щелкаешь на блок, то внутренний блок скрывается) Данный метод не работает если щелкать подряд меду этими блоками(внутренние блоки перестают закрываться).

Возьми напиши плагин, который при щелчке на ссылку будет скрывать все твои меню. И тогда алгоритм работает на множествах ссылках )))

Гость
03.04.2019, 08:24

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

$(document).ready(function () {
$(".hs-menubar").hsMenu(); 
$(".hamburger").click(function(){
$(this).toggleClass("is-active");
});
}); 

$(document).click(function(event) { 
$target = $(event.target);
if(!$target.closest('.hamburger').length && 
$('.hamburger').toggleClass("is-active"));
});

ЧеловекКоторомуПомогЭтотПост
22.04.2020, 16:48

чувак храни тебя Боже !!! Ты мне очень помог !!! Спасибо огромнейшее, я в 2020 не мог найти нужное мне решение и нашёл его тут !!!

Добавить комментарий