xandeadx.ru Блог музицирующего веб-девелопера

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

Опубликовано в

Распространённая задача — скрыть всплывающее 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();
        }
    });
});
Похожие записи

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

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

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

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

parents(selector) подойдёт

Но, что делать, если jquery старый?

http://drupal.org/project/jquery_update

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

$('#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')

Спасибо xandeadx и спасибо Ch

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

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

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

Если поставить 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;
}

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

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

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

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

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

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

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

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

/*Закриття форми при кліку поза її межами*/
jQuery(function($) {
$(document).mouseup(function (e) {
var div = $(".close_form");
if (!div.is(e.target)
&& div.has(e.target).length === 0) {
div.hide();
$('.black').hide();
}
});
});

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

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании