Используйте jQuery, чтобы скрыть DIV, когда пользователь нажимает за его пределами


968

Я использую этот код:

$('body').click(function() {
   $('.form_wrapper').hide();
});

$('.form_wrapper').click(function(event){
   event.stopPropagation();
});

И этот HTML :

<div class="form_wrapper">
   <a class="agree" href="javascript:;">I Agree</a>
   <a class="disagree" href="javascript:;">Disagree</a>
</div>

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


6
Используя обычный javascript, вы можете попробовать что-то вроде этого: jsfiddle.net/aamir/y7mEY
Afridi

использовать $('html')или $(document)будет лучше, чем$('body')
Adrien Be

Ответы:


2485

Была такая же проблема, придумал это простое решение. Это даже работает рекурсивно:

$(document).mouseup(function(e) 
{
    var container = $("YOUR CONTAINER SELECTOR");

    // if the target of the click isn't the container nor a descendant of the container
    if (!container.is(e.target) && container.has(e.target).length === 0) 
    {
        container.hide();
    }
});

19
Просто поместите это в мой проект, но с небольшой корректировкой, используя массив элементов, чтобы пройти через них все сразу. jsfiddle.net/LCB5W
Томас

5
@mpelzsherman Многие люди отмечали, что фрагмент работает на сенсорных устройствах, но после того, как сообщение было отредактировано, эти комментарии несколько исчезли. TBH Я не знаю, использовал ли я «mouseup» по определенной причине, но если он также работает с «щелчком», я не вижу причин, почему вы не должны использовать «щелчок».

6
Мне нужно, чтобы контейнер был скрыт один раз с этим событием, этот обратный вызов должен быть уничтожен при использовании. Для этого я использовал пространство имен для события click с привязкой («click.namespace»), а когда событие произошло, я вызываю unbind («click.namespace»). И, наконец, я использовал $ (e.target) .closest (". Container"). Length, чтобы распознать контейнер ... Итак, я не использовал никакой хитрости из этого ответа: D
Loenix

80
Вспоминая использовать $("YOUR CONTAINER SELECTOR").unbind( 'click', clickDocument );только рядом .hide(). Так documentчто не слушайте клики.
brasofilo

12
Для лучших практик я написал $(document).on("mouseup.hideDocClick", function () { ... });в функции, которая открывает контейнер, и $(document).off('.hideDocClick');в функции скрытия. Используя пространства имен, я не удаляю других возможных mouseupслушателей, прикрепленных к документу.
campsjos

204

Вы бы лучше пойти с чем-то вроде этого:

var mouse_is_inside = false;

$(document).ready(function()
{
    $('.form_content').hover(function(){ 
        mouse_is_inside=true; 
    }, function(){ 
        mouse_is_inside=false; 
    });

    $("body").mouseup(function(){ 
        if(! mouse_is_inside) $('.form_wrapper').hide();
    });
});

Как умно! Эта техника стандартная?
Advait

@advait Я не видел его раньше. Все дело в hoverобработчике событий, который открывает много возможностей.
Макрам Салех

5
Я не считаю это хорошим решением, поскольку оно позволяет людям думать, что можно заполнять объект window (= используя глобальные переменные).

1
Просто чтобы добавить что-то к тому, что сказал @ prc322, вы можете обернуть свой код анонимной функцией и сразу вызвать ее. (function() { // ... code })(); Я не помню название этой модели, но она очень полезна! Все ваши объявленные переменные будут находиться внутри функции и не будут загрязнять глобальное пространство имен.
Pedromanoel

3
@ prc322 Если вы даже не знаете, как изменить область действия переменной, то вы правы, это решение вам не подходит ... и JavaScript тоже не подходит. Если вы просто копируете и вставляете код из Stack Overflow, у вас будет гораздо больше проблем, чем, возможно, что-то перезаписываете в объекте окна.
Гэвин

87

Этот код обнаруживает любое событие нажатия на странице, а затем скрывает #CONTAINERэлемент, если и только если элемент, по которому щелкнули, не был ни #CONTAINERэлементом, ни одним из его потомков.

$(document).on('click', function (e) {
    if ($(e.target).closest("#CONTAINER").length === 0) {
        $("#CONTAINER").hide();
    }
});

Это потрясающе!!
Мохд Абдул Муджиб

@ 9KSoft Я рад, что смог вам помочь. Спасибо за ваш отзыв и удачи.
Дело

Это решение отлично работает для меня, используя div в качестве контейнера!
JCO9

76

Возможно, вы захотите проверить цель события click, которое запускается для тела, а не полагаться на stopPropagation.

Что-то вроде:

$("body").click
(
  function(e)
  {
    if(e.target.className !== "form_wrapper")
    {
      $(".form_wrapper").hide();
    }
  }
);

Кроме того, элемент body может не включать все визуальное пространство, отображаемое в браузере. Если вы заметили, что ваши клики не регистрируются, вам может понадобиться добавить обработчик кликов для элемента HTML.


Да, теперь ссылки работают! Но по какой-то причине, когда я нажимаю на ссылку, она запускается дважды.
Скотт Ю - строит материал

Я закончил тем, что использовал вариант этого. Сначала я проверяю, видим ли элемент, затем, если target.hasClass, я его скрываю.
Хоки

и не забывайте, e.stopPropagation();если у вас есть другой слушатель щелчка
Дарин Колев

2
-1. Это скрывает, form_wrapperкогда вы нажимаете на одного из его дочерних элементов, что не является желаемым поведением. Вместо этого используйте ответ prc322.
Марк Амери

38

Live DEMO

Проверьте, что область щелчка не находится в целевом элементе или в его дочернем элементе.

$(document).click(function (e) {
    if ($(e.target).parents(".dropdown").length === 0) {
        $(".dropdown").hide();
    }
});

ОБНОВИТЬ:

JQuery остановить распространение является лучшим решением

Live DEMO

$(".button").click(function(e){
    $(".dropdown").show();
     e.stopPropagation();
});

$(".dropdown").click(function(e){
    e.stopPropagation();
});

$(document).click(function(){
    $(".dropdown").hide();
});

Спасибо за обновление, отлично! Работает ли на сенсорных устройствах?
FFish

1
В этом случае у вас есть несколько выпадающих на странице. Я думаю, вам нужно закрыть все выпадающие, прежде чем открывать clickedодин. В противном случае это stopPropagationсделало бы возможным открытие нескольких раскрывающихся списков одновременно.
T04435

19
$(document).click(function(event) {
    if ( !$(event.target).hasClass('form_wrapper')) {
         $(".form_wrapper").hide();
    }
});

2
Хммм ... Если я нажму на что-то ВНУТРИ div, почему-то весь div исчезнет.
Скотт Ю - строит материал

11
Вместо того, чтобы проверять, есть ли у цели класс, попробуйте: if ($ (event.target) .closest ('. Form_wrapper) .get (0) == null) {$ (". Form_wrapper"). Hide (); } Это гарантирует, что нажатие на элементы внутри div не будет скрывать div.
Джон Хаагер

17

Обновил решение до:

  • используйте вместо этого mouseenter и mouseleave
  • при наведении курсора

var mouseOverActiveElement = false;

$('.active').live('mouseenter', function(){
    mouseOverActiveElement = true; 
}).live('mouseleave', function(){ 
    mouseOverActiveElement = false; 
});
$("html").click(function(){ 
    if (!mouseOverActiveElement) {
        console.log('clicked outside active element');
    }
});

1
.liveсейчас устарела ; используйте .onвместо.
Бретт

15

Решение без jQuery для самого популярного ответа :

document.addEventListener('mouseup', function (e) {
    var container = document.getElementById('your container ID');

    if (!container.contains(e.target)) {
        container.style.display = 'none';
    }
}.bind(this));

MDN: https://developer.mozilla.org/en/docs/Web/API/Node/contains


bindтам не работает. Не могли бы вы исправить эту функцию, чтобы она работала?
Мемо

9

Живая демоверсия с ESCфункциональностью

Работает как на настольном, так и на мобильном

var notH = 1,
    $pop = $('.form_wrapper').hover(function(){ notH^=1; });

$(document).on('mousedown keydown', function( e ){
  if(notH||e.which==27) $pop.hide();
});

Если в каком-то случае вам нужно быть уверенным, что ваш элемент действительно виден, когда вы нажимаете на документ: if($pop.is(':visible') && (notH||e.which==27)) $pop.hide();


8

Не будет ли что-то подобное этой работой?

$("body *").not(".form_wrapper").click(function() {

});

или

$("body *:not(.form_wrapper)").click(function() {

});

4
Этот ответ не правильный. Как и многие ответы здесь, это будет скрывать, .form_wrapperкогда вы нажимаете на своих детей (среди других проблем).
Марк Амери

6

Даже спальный

$("html").click(function(){ 
    $(".wrapper:visible").hide();
});

4
Этот ответ не правильный. Это будет скрывать .wrapperнезависимо от того, где вы нажимаете на страницу, а это не то, о чем просили.
Марк Амери

6

Вместо прослушивания каждого отдельного щелчка по DOM, чтобы скрыть один конкретный элемент, вы можете установить tabindexродительский<div> и прослушатьfocusout события.

Установка tabindexубедится, чтоblur события на<div> (обычно это не так).

Итак, ваш HTML будет выглядеть так:

<div class="form_wrapper" tabindex="0">
    <a class="agree" href="javascript:;">I Agree</a>
    <a class="disagree" href="javascript:;">Disagree</a>
</div>

И ваш JS:

$('.form_wrapper').on('focusout', function(event){
    $('.form_wrapper').hide();
});

5

А для сенсорных устройств, таких как IPAD и IPHONE, мы можем использовать следующий код

$(document).on('touchstart', function (event) {
var container = $("YOUR CONTAINER SELECTOR");

if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0) // ... nor a descendant of the container
    {
        container.hide();
    }
});

5

Вот jsfiddle, который я нашел в другом потоке, также работает с ключом esc: http://jsfiddle.net/S5ftb/404

    var button = $('#open')[0]
    var el     = $('#test')[0]

    $(button).on('click', function(e) {
      $(el).show()
      e.stopPropagation()
    })

    $(document).on('click', function(e) {
      if ($(e.target).closest(el).length === 0) {
        $(el).hide()
      }
    })

    $(document).on('keydown', function(e) {
      if (e.keyCode === 27) {
        $(el).hide()
      }
    })

Я вижу, что он определяет, находится ли событие click в элементе #test ... пробовал проверять ссылки как jsfiddle.net/TA96A и похоже, что они могут работать.
Томас В.

Да, похоже, что jsfiddle блокирует внешние ссылки. Если вы используете http: // jsfiddle.net, вы увидите, что страница результатов обрабатывает ссылку :)
djv

5

Построен из удивительного ответа prc322.

function hideContainerOnMouseClickOut(selector, callback) {
  var args = Array.prototype.slice.call(arguments); // Save/convert arguments to array since we won't be able to access these within .on()
  $(document).on("mouseup.clickOFF touchend.clickOFF", function (e) {
    var container = $(selector);

    if (!container.is(e.target) // if the target of the click isn't the container...
        && container.has(e.target).length === 0) // ... nor a descendant of the container
    {
      container.hide();
      $(document).off("mouseup.clickOFF touchend.clickOFF");
      if (callback) callback.apply(this, args);
    }
  });
}

Это добавляет пару вещей ...

  1. Помещается в функцию с обратным вызовом с «неограниченными» аргументами
  2. Добавлен вызов joffery's .off () в паре с пространством имен события, чтобы отсоединить событие от документа после его запуска.
  3. Включенный набор для мобильных функций

Я надеюсь, что это помогает кому-то!



4

(Просто добавлю к ответу prc322.)

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

$(document).mouseup(function (e)
{
    var container = $("YOUR CONTAINER SELECTOR");

    if (!$("a").is(e.target) // if the target of the click isn't a link ...
        && !container.is(e.target) // ... or the container ...
        && container.has(e.target).length === 0) // ... or a descendant of the container
    {
        container.hide();
    }
});

Это потому, что некоторые ссылки на моем сайте добавляют новый контент на страницу. Если этот новый контент добавляется одновременно с исчезновением навигационного меню, это может дезориентировать пользователя.


4

Так много ответов, должно быть право прохода, чтобы добавить один ... Я не видел текущих (jQuery 3.1.1) ответов - так:

$(function() {
    $('body').on('mouseup', function() {
        $('#your-selector').hide();
    });
});

3
var n = 0;
$("#container").mouseenter(function() {
n = 0;

}).mouseleave(function() {
n = 1;
});

$("html").click(function(){ 
if (n == 1) {
alert("clickoutside");
}
});

3
 $('body').click(function(event) {
    if (!$(event.target).is('p'))
    {
        $("#e2ma-menu").hide();
    }
});

pэто имя элемента. Где также можно передать идентификатор или имя класса или элемента.


3

Верните false, если вы нажмете на .form_wrapper:

$('body').click(function() {
  $('.form_wrapper').click(function(){
  return false
});
   $('.form_wrapper').hide();
});

//$('.form_wrapper').click(function(event){
//   event.stopPropagation();
//});

3

Прикрепите событие click к элементам верхнего уровня за пределами оболочки формы, например:

$('#header, #content, #footer').click(function(){
    $('.form_wrapper').hide();
});

Это также будет работать на сенсорных устройствах, просто убедитесь, что вы не включили родительский элемент .form_wrapper в свой список селекторов.


3

var exclude_div = $("#ExcludedDiv");;  
$(document).click(function(e){
   if( !exclude_div.is( e.target ) )  // if target div is not the one you want to exclude then add the class hidden
        $(".myDiv1").addClass("hidden");  

}); 

FIDDLE


3

$(document).ready(function() {
	$('.modal-container').on('click', function(e) {
	  if(e.target == $(this)[0]) {
		$(this).removeClass('active'); // or hide()
	  }
	});
});
.modal-container {
	display: none;
	justify-content: center;
	align-items: center;
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background-color: rgba(0,0,0,0.5);
	z-index: 999;
}

.modal-container.active {
    display: flex;  
}

.modal {
	width: 50%;
	height: auto;
	margin: 20px;
	padding: 20px;
	background-color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="modal-container active">
	<div class="modal">
		<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ac varius purus. Ut consectetur viverra nibh nec maximus. Nam luctus ligula quis arcu accumsan euismod. Pellentesque imperdiet volutpat mi et cursus. Sed consectetur sed tellus ut finibus. Suspendisse porttitor laoreet lobortis. Nam ut blandit metus, ut interdum purus.</p>
	</div>
</div>


3

Скопировано с https://sdtuts.com/click-on-not-specified-element/

Живая демоверсия http://demos.sdtuts.com/click-on-specified-element

$(document).ready(function () {
    var is_specified_clicked;
    $(".specified_element").click(function () {
        is_specified_clicked = true;
        setTimeout(function () {
            is_specified_clicked = false;
        }, 200);
    })
    $("*").click(function () {
        if (is_specified_clicked == true) {
//WRITE CODE HERE FOR CLICKED ON OTHER ELEMENTS
            $(".event_result").text("you were clicked on specified element");
        } else {
//WRITE CODE HERE FOR SPECIFIED ELEMENT CLICKED
            $(".event_result").text("you were clicked not on specified element");
        }
    })
})

2

я сделал это так:

var close = true;

$(function () {

    $('body').click (function(){

        if(close){
            div.hide();
        }
        close = true;
    })


alleswasdenlayeronclicknichtschliessensoll.click( function () {   
        close = false;
    });

});

2
dojo.query(document.body).connect('mouseup',function (e)
{
    var obj = dojo.position(dojo.query('div#divselector')[0]);
    if (!((e.clientX > obj.x && e.clientX <(obj.x+obj.w)) && (e.clientY > obj.y && e.clientY <(obj.y+obj.h))) ){
        MyDive.Hide(id);
    }
});

2

С помощью этого кода вы можете скрыть столько элементов, сколько хотите

var boxArray = ["first element's id","second element's id","nth element's id"];
   window.addEventListener('mouseup', function(event){
   for(var i=0; i < boxArray.length; i++){
    var box = document.getElementById(boxArray[i]);
    if(event.target != box && event.target.parentNode != box){
        box.style.display = 'none';
    }
   }
})

1

Что вы можете сделать, это привязать событие щелчка к документу, который будет скрывать раскрывающийся список, если щелкнет что-то за пределами раскрывающегося списка, но не будет скрывать его, если щелкнуть что-то внутри раскрывающегося списка, поэтому ваше событие «показ» (или слайд-шоу или что-то еще) показывает выпадающий список)

    $('.form_wrapper').show(function(){

        $(document).bind('click', function (e) {
            var clicked = $(e.target);
            if (!clicked.parents().hasClass("class-of-dropdown-container")) {
                 $('.form_wrapper').hide();
            }
        });

    });

Затем, скрывая его, открепите событие click

$(document).unbind('click');

0

Согласно документам , .blur()работает больше, чем <input>тег. Например:

$('.form_wrapper').blur(function(){
   $(this).hide();
});

-1, не работает. Очень интересная идея, но документы JQuery неверны. См. Например, developer.mozilla.org/en-US/docs/Web/API/… «В отличие от MSIE, в которой почти все виды элементов получают событие размытия, - почти все виды элементов в браузерах Gecko НЕ работать с этим событием. " Кроме того, протестировано в Chrome и divникогда не размыто - события размытия не могут даже пузыриться от их детей. Наконец, даже если вышеупомянутое не соответствует действительности, это будет работать, только если вы удостоверились, что объект .form_wrapperбыл в фокусе до того, как пользователь щелкнул его.
Марк Амери
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.