Как определить клик вне элемента?

У меня есть некоторые HTML-меню, которые я показываю полностью, когда пользователь нажимает на заголовок этих меню. Я хотел бы скрыть эти элементы, когда пользователь щелкает за пределами области меню.

Что-то вроде этого возможно с jQuery?

$("#menuscontainer").clickOutsideThisElement(function() {
    // Hide the menus
});
1819
задан Sergio del Amo 30 сент. '08 в 16:17
источник поделиться

70 ответов

  • 1
  • 2
  • 3

ПРИМЕЧАНИЕ. Использование stopEventPropagation() - это то, чего следует избегать, поскольку он нарушает нормальный поток событий в DOM. Подробнее см. в этой статье. Вместо этого используйте этот метод.

Прикрепите событие клика к телу документа, который закрывает окно. Прикрепите отдельное событие клика к окну, которое прекратит распространение в тело документа.

$(window).click(function() {
//Hide the menus if visible
});

$('#menucontainer').click(function(event){
    event.stopPropagation();
});
1536
ответ дан Eran Galperin 30 сент. '08 в 16:38
источник поделиться

Вы можете прослушивать событие click на document, а затем убедитесь, что #menucontainer не является предком или объектом щелкнутого элемента, используя .closest().

Если это не так, то элемент с щелчком находится за пределами #menucontainer, и вы можете с уверенностью скрыть его.

$(document).click(function(event) { 
    if(!$(event.target).closest('#menucontainer').length) {
        if($('#menucontainer').is(":visible")) {
            $('#menucontainer').hide();
        }
    }        
});

Изменить - 2017-06-23

Вы также можете очистить после прослушивателя событий, если вы планируете отклонить меню и хотите прекратить прослушивание событий. Эта функция очищает только вновь созданный слушатель, сохраняя любые другие прослушиватели кликов на document. С синтаксисом ES2015:

export function hideOnClickOutside(selector) {
  const outsideClickListener = (event) => {
    if (!$(event.target).closest(selector).length) {
      if ($(selector).is(':visible')) {
        $(selector).hide()
        removeClickListener()
      }
    }
  }

  const removeClickListener = () => {
    document.removeEventListener('click', outsideClickListener)
  }

  document.addEventListener('click', outsideClickListener)
}
1001
ответ дан Art 12 июня '10 в 11:35
источник поделиться

Как обнаружить клик вне элемента?

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

Я хотел бы скрыть эти элементы, когда пользователь щелкает за пределами области меню.

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

Подсказка: это слово "click"!

На самом деле вы не хотите привязывать обработчики кликов.

Если вы привязываете обработчики кликов, чтобы закрыть диалоговое окно, вы уже потерпели неудачу. Причина, по которой вы потерпели неудачу, состоит в том, что не каждый вызывает события click. Пользователи, не использующие мышь, смогут выйти из вашего диалогового окна (и ваше всплывающее меню, возможно, является типом диалога), нажав Tab, и тогда они не смогут прочитать содержимое за диалогом без последующего запуска a click.

Так что давайте перефразируем вопрос.

Как закрыть диалог, когда пользователь закончил с ним?

Это цель. К сожалению, теперь нам нужно связать событие userisfinishedwiththedialog, и это связывание не так просто.

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

focusout событие

Хорошим началом является определение того, оставил ли фокус диалог.

Подсказка: будьте осторожны с событием blur, blur не распространяется, если событие было связано с фазой барботирования!

jQuery focusout будет прекрасно. Если вы не можете использовать jQuery, вы можете использовать blur на этапе захвата:

element.addEventListener('blur', ..., true);
//                       use capture: ^^^^

Кроме того, для многих диалогов вам нужно будет позволить контейнеру получить фокус. Добавьте tabindex="-1", чтобы диалоговое окно могло получать фокус динамически, не прерывая при этом поток табуляции.

$('a').on('click', function () {
  $(this.hash).toggleClass('active').focus();
});

$('div').on('focusout', function () {
  $(this).removeClass('active');
});
div {
  display: none;
}
.active {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
  Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>

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

Во-первых, ссылка в диалоговом окне не доступна. Попытка щелкнуть по нему или вкладку к ней приведет к закрытию диалогового окна до того, как произойдет взаимодействие. Это связано с тем, что фокусировка внутреннего элемента вызывает событие focusout перед тем, как снова запустить событие focusin.

Исправление - очередь на изменение состояния в цикле событий. Это можно сделать, используя setImmediate(...) или setTimeout(..., 0) для браузеров, которые не поддерживают setImmediate. После того, как он поставлен в очередь, он может быть отменен последующим focusin:

$('.submenu').on({
  focusout: function (e) {
    $(this).data('submenuTimer', setTimeout(function () {
      $(this).removeClass('submenu--active');
    }.bind(this), 0));
  },
  focusin: function (e) {
    clearTimeout($(this).data('submenuTimer'));
  }
});

$('a').on('click', function () {
  $(this.hash).toggleClass('active').focus();
});

$('div').on({
  focusout: function () {
    $(this).data('timer', setTimeout(function () {
      $(this).removeClass('active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this).data('timer'));
  }
});
div {
  display: none;
}
.active {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
  Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>

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

Как и в предыдущем выпуске, нужно управлять состоянием фокусировки. Учитывая, что изменение состояния уже поставлено в очередь, это всего лишь вопрос обработки фокусных событий в диалоговом режиме:

Это должно выглядеть знакомо
$('a').on({
  focusout: function () {
    $(this.hash).data('timer', setTimeout(function () {
      $(this.hash).removeClass('active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this.hash).data('timer'));  
  }
});

$('a').on('click', function () {
  $(this.hash).toggleClass('active').focus();
});

$('div').on({
  focusout: function () {
    $(this).data('timer', setTimeout(function () {
      $(this).removeClass('active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this).data('timer'));
  }
});

$('a').on({
  focusout: function () {
    $(this.hash).data('timer', setTimeout(function () {
      $(this.hash).removeClass('active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this.hash).data('timer'));  
  }
});
div {
  display: none;
}
.active {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
  Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>

Esc ключ

Если вы считаете, что все сделано, управляя состояниями фокусировки, вы можете сделать больше, чтобы упростить работу с пользователем.

Это часто бывает "приятно иметь", но обычно бывает, что когда у вас есть модальный или всплывающий файл любого типа, который закрывает его клавиша Esc.

keydown: function (e) {
  if (e.which === 27) {
    $(this).removeClass('active');
    e.preventDefault();
  }
}

$('a').on('click', function () {
  $(this.hash).toggleClass('active').focus();
});

$('div').on({
  focusout: function () {
    $(this).data('timer', setTimeout(function () {
      $(this).removeClass('active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this).data('timer'));
  },
  keydown: function (e) {
    if (e.which === 27) {
      $(this).removeClass('active');
      e.preventDefault();
    }
  }
});

$('a').on({
  focusout: function () {
    $(this.hash).data('timer', setTimeout(function () {
      $(this.hash).removeClass('active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this.hash).data('timer'));  
  }
});
div {
  display: none;
}
.active {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
  Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>

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

click: function (e) {
  $(this.hash)
    .toggleClass('submenu--active')
    .find('a:first')
    .focus();
  e.preventDefault();
}

$('.menu__link').on({
  click: function (e) {
    $(this.hash)
      .toggleClass('submenu--active')
      .find('a:first')
      .focus();
    e.preventDefault();
  },
  focusout: function () {
    $(this.hash).data('submenuTimer', setTimeout(function () {
      $(this.hash).removeClass('submenu--active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this.hash).data('submenuTimer'));  
  }
});

$('.submenu').on({
  focusout: function () {
    $(this).data('submenuTimer', setTimeout(function () {
      $(this).removeClass('submenu--active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this).data('submenuTimer'));
  },
  keydown: function (e) {
    if (e.which === 27) {
      $(this).removeClass('submenu--active');
      e.preventDefault();
    }
  }
});
.menu {
  list-style: none;
  margin: 0;
  padding: 0;
}
.menu:after {
  clear: both;
  content: '';
  display: table;
}
.menu__item {
  float: left;
  position: relative;
}

.menu__link {
  background-color: lightblue;
  color: black;
  display: block;
  padding: 0.5em 1em;
  text-decoration: none;
}
.menu__link:hover,
.menu__link:focus {
  background-color: black;
  color: lightblue;
}

.submenu {
  border: 1px solid black;
  display: none;
  left: 0;
  list-style: none;
  margin: 0;
  padding: 0;
  position: absolute;
  top: 100%;
}
.submenu--active {
  display: block;
}

.submenu__item {
  width: 150px;
}

.submenu__link {
  background-color: lightblue;
  color: black;
  display: block;
  padding: 0.5em 1em;
  text-decoration: none;
}

.submenu__link:hover,
.submenu__link:focus {
  background-color: black;
  color: lightblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="menu">
  <li class="menu__item">
    <a class="menu__link" href="#menu-1">Menu 1</a>
    <ul class="submenu" id="menu-1" tabindex="-1">
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li>
    </ul>
  </li>
  <li class="menu__item">
    <a  class="menu__link" href="#menu-2">Menu 2</a>
    <ul class="submenu" id="menu-2" tabindex="-1">
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li>
    </ul>
  </li>
</ul>
lorem ipsum <a href="http://example.com/">dolor</a> sit amet.

Роли WAI-ARIA и другая поддержка доступности

Этот ответ, надеюсь, охватывает основы доступной поддержки клавиатуры и мыши для этой функции, но поскольку он уже довольно значителен, я собираюсь избегать обсуждения ролей и атрибутов WAI-ARIA, однако я настоятельно рекомендую, чтобы разработчики ссылались на спецификацию для подробностей о том, какие роли они должны использовать, и любых других соответствующих атрибутах.

137
ответ дан zzzzBov 12 июля '16 в 2:29
источник поделиться

Другие решения здесь не работали для меня, поэтому я должен был использовать:

if(!$(event.target).is('#foo'))
{
    // hide menu
}
118
ответ дан Dennis 07 июля '09 в 2:10
источник поделиться

У меня есть приложение, которое работает аналогично примеру Eran, за исключением того, что я прикрепляю событие click к телу при открытии меню... Kinda вроде этого:

$('#menucontainer').click(function(event) {
  $('html').one('click',function() {
    // Hide the menus
  });

  event.stopPropagation();
});

Дополнительная информация о jQuery one() функция

114
ответ дан Joe Lencioni 30 сент. '08 в 21:13
источник поделиться
$("#menuscontainer").click(function() {
    $(this).focus();
});
$("#menuscontainer").blur(function(){
    $(this).hide();
});

Работает для меня просто отлично.

31
ответ дан user212621 17 нояб. '09 в 9:13
источник поделиться

Теперь для этого есть плагин: внешние события (сообщение в блоге)

Следующее происходит, когда обработчик clickoutside (WLOG) привязан к элементу:

  • элемент добавляется в массив, который содержит все элементы с обработчиками clickoutside.
  • a (namespaced) обработчик клика привязан к документу (если он еще не существует)
  • при любом щелчке в документе событие clickoutside запускается для тех элементов в этом массиве, которые не равны или родительский объект цели-клика
  • Кроме того, event.target для события clickoutside установлен на элемент, на который пользователь нажал (чтобы вы даже знали, что пользователь нажал, а не только, что он щелкнул снаружи).

Таким образом, никакие события не прекращаются из-за распространения, а дополнительные обработчики кликов могут использоваться "выше" с помощью внешнего обработчика.

30
ответ дан Wolfram 05 апр. '10 в 13:07
источник поделиться

Это сработало для меня отлично!

$('html').click(function (e) {
    if (e.target.id == 'YOUR-DIV-ID') {
        //do something
    } else {
        //do something
    }
});
26
ответ дан srinath 04 июня '12 в 17:08
источник поделиться

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

Не найдя удовлетворительных ответов, я попросил написать этот пост в блоге на днях. Для более педантичного, есть несколько ошибок, чтобы принять к сведению:

  • Если вы присоедините обработчик события клика к элементу body во время клика, обязательно дождитесь второго щелчка перед закрытием меню и отвяжите событие. В противном случае событие клика, открывшее меню, выйдет на экран слушателя, который должен закрыть меню.
  • Если вы используете event.stopPropogation() в событии клика, никакие другие элементы на вашей странице не могут иметь функцию click-where-to-close.
  • Прикрепление обработчика события click к элементу body неограниченно не является эффективным решением
  • Сравнение цели события и его родителей с создателем обработчика предполагает, что вы хотите закрыть меню при нажатии на него, когда то, что вы действительно хотите, это закрыть его, когда вы нажимаете в любом месте страницы.
  • Прослушивание событий на элементе body сделает ваш код более хрупким. Стиль невинно, как это могло бы сломать его: body { margin-left:auto; margin-right: auto; width:960px;}
20
ответ дан 34m0 19 мая '11 в 0:15
источник поделиться

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

$('#menuscontainer').click(function(event) {
    //your code that shows the menus fully

    //now set up an event listener so that clicking anywhere outside will close the menu
    $('html').click(function(event) {
        //check up the tree of the click target to check whether user has clicked outside of menu
        if ($(event.target).parents('#menuscontainer').length==0) {
            // your code to hide menu

            //this event listener has done its job so we can unbind it.
            $(this).unbind(event);
        }

    })
});
19
ответ дан benb 22 дек. '11 в 14:59
источник поделиться

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

Или проверьте положение щелчка и посмотрите, содержится ли он в области меню.

17
ответ дан Chris MacDonald 30 сент. '08 в 16:20
источник поделиться

После исследования я нашел три рабочих решения (я забыл ссылки на страницы для справки)

Первое решение

<script>
    //The good thing about this solution is it doesn't stop event propagation.

    var clickFlag = 0;
    $('body').on('click', function () {
        if(clickFlag == 0) {
            console.log('hide element here');
            /* Hide element here */
        }
        else {
            clickFlag=0;
        }
    });
    $('body').on('click','#testDiv', function (event) {
        clickFlag = 1;
        console.log('showed the element');
        /* Show the element */
    });
</script>

Второе решение

<script>
    $('body').on('click', function(e) {
        if($(e.target).closest('#testDiv').length == 0) {
           /* Hide dropdown here */
        }
    });
</script>

Третье решение

<script>
    var specifiedElement = document.getElementById('testDiv');
    document.addEventListener('click', function(event) {
        var isClickInside = specifiedElement.contains(event.target);
        if (isClickInside) {
          console.log('You clicked inside')
        }
        else {
          console.log('You clicked outside')
        }
    });
</script>
17
ответ дан Rameez Rami 02 нояб. '15 в 11:33
источник поделиться

Solution1

Вместо использования event.stopPropagation(), который может иметь некоторые побочные эффекты, просто определите простую переменную флага и добавьте одно условие if. Я тестировал это и работал нормально без каких-либо побочных эффектов stopPropagation:

var flag = "1";
$('#menucontainer').click(function(event){
    flag = "0"; // flag 0 means click happened in the area where we should not do any action
});

$('html').click(function() {
    if(flag != "0"){
        // Hide the menus if visible
    }
    else {
        flag = "1";
    }
});

Solution2

С помощью простого условия if:

$(document).on('click', function(event){
    var container = $("#menucontainer");
    if (!container.is(event.target) &&            // If the target of the click isn't the container...
        container.has(event.target).length === 0) // ... nor a descendant of the container
    {
        // Do whatever you want to do when click is outside the element
    }
});
14
ответ дан Iman Sedighi 28 янв. '15 в 20:24
источник поделиться

В качестве варианта:

var $menu = $('#menucontainer');
$(document).on('click', function (e) {

    // If element is opened and click target is outside it, hide it
    if ($menu.is(':visible') && !$menu.is(e.target) && !$menu.has(e.target).length) {
        $menu.hide();
    }
});

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

13
ответ дан Bohdan Lyzanets 24 июля '14 в 12:41
источник поделиться

Простым решением для ситуации является:

$(document).mouseup(function (e)
{
    var container = $("YOUR SELECTOR"); // Give you class or ID

    if (!container.is(e.target) &&            // If the target of the click is not the desired div or section
        container.has(e.target).length === 0) // ... nor a descendant-child of the container
    {
        container.hide();
    }
});

Вышеупомянутый script скроет div, если вне события div запускается событие click.

Дополнительную информацию вы можете найти в следующем блоге: http://www.codecanal.com/detect-click-outside-div-using-javascript/

13
ответ дан Jitendra Damor 15 дек. '15 в 6:50
источник поделиться

У меня был успех с чем-то вроде этого:

var $menuscontainer = ...;

$('#trigger').click(function() {
  $menuscontainer.show();

  $('body').click(function(event) {
    var $target = $(event.target);

    if ($target.parents('#menuscontainer').length == 0) {
      $menuscontainer.hide();
    }
  });
});

Логика такова: когда показан #menuscontainer, привяжите обработчик клика к телу, который скрывает #menuscontainer только в том случае, если цель (щелчка) не является дочерним элементом #menuscontainer.

12
ответ дан Chu Yeow 02 дек. '10 в 12:53
источник поделиться

Я нашел этот метод в некотором плагине календаря jQuery.

function ClickOutsideCheck(e)
{
  var el = e.target;
  var popup = $('.popup:visible')[0];
  if (popup==undefined)
    return true;

  while (true){
    if (el == popup ) {
      return true;
    } else if (el == document) {
      $(".popup").hide();
      return false;
    } else {
      el = $(el).parent()[0];
    }
  }
};

$(document).bind('mousedown.popup', ClickOutsideCheck);
12
ответ дан nazar kuliyev 28 июля '11 в 17:06
источник поделиться

Вместо использования прерывания потока, события размытия/фокусировки или любой другой сложной техники просто сопоставьте поток событий с родством элементов:

$(document).on("click.menu-outside", function(event){
    // Test if target and it parent aren't #menuscontainer
    // That means the click event occur on other branch of document tree
    if(!$(event.target).parents().andSelf().is("#menuscontainer")){
        // Click outisde #menuscontainer
        // Hide the menus (but test if menus aren't already hidden)
    }
});

Чтобы удалить прослушиватель внешних событий, просто:

$(document).off("click.menu-outside");
8
ответ дан mems 05 июня '13 в 18:05
источник поделиться

Вот решение для ванильного JavaScript для будущих зрителей.

При щелчке по любому элементу внутри документа, если щелкнул идентификатор элемента clicked, или скрытый элемент не скрыт, а скрытый элемент не содержит элемент с щелчком, переключите элемент.

(function () {
    "use strict";
    var hidden = document.getElementById('hidden');
    document.addEventListener('click', function (e) {
        if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none';
    }, false);
})();

(function () {
    "use strict";
    var hidden = document.getElementById('hidden');
    document.addEventListener('click', function (e) {
        if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none';
    }, false);
})();
<a href="javascript:void(0)" id="toggle">Toggle Hidden Div</a>
<div id="hidden" style="display: none;">This content is normally hidden. click anywhere other than this content to make me disappear</div>

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

  • Добавить имя класса hidden в складной элемент.
  • При щелчке документа закройте все скрытые элементы, которые не содержат элемент с кликом и не скрыты.
  • Если щелкнутый элемент является переключателем, переключите указанный элемент.

(function () {
    "use strict";
    var hiddenItems = document.getElementsByClassName('hidden'), hidden;
    document.addEventListener('click', function (e) {
        for (var i = 0; hidden = hiddenItems[i]; i++) {
            if (!hidden.contains(e.target) && hidden.style.display != 'none')
                hidden.style.display = 'none';
        }
        if (e.target.getAttribute('data-toggle')) {
            var toggle = document.querySelector(e.target.getAttribute('data-toggle'));
            toggle.style.display = toggle.style.display == 'none' ? 'block' : 'none';
        }
    }, false);
})();
<a href="javascript:void(0)" data-toggle="#hidden1">Toggle Hidden Div</a>
<div class="hidden" id="hidden1" style="display: none;" data-hidden="true">This content is normally hidden</div>
<a href="javascript:void(0)" data-toggle="#hidden2">Toggle Hidden Div</a>
<div class="hidden" id="hidden2" style="display: none;" data-hidden="true">This content is normally hidden</div>
<a href="javascript:void(0)" data-toggle="#hidden3">Toggle Hidden Div</a>
<div class="hidden" id="hidden3" style="display: none;" data-hidden="true">This content is normally hidden</div>
7
ответ дан Tiny Giant 20 мая '15 в 1:52
источник поделиться

Событие имеет свойство, называемое event.path элемента, который является "статическим упорядоченным списком всех его предков в порядке дерева". Чтобы проверить, произошло ли событие из определенного элемента DOM или одного из его дочерних элементов, просто проверьте путь к этому конкретному элементу DOM. Он также может использоваться для проверки нескольких элементов логически OR при проверке элемента в функции some.

$("body").click(function() {
  target = document.getElementById("main");
  flag = event.path.some(function(el, i, arr) {
    return (el == target)
  })
  if (flag) {
    console.log("Inside")
  } else {
    console.log("Outside")
  }
});
#main {
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main">
  <ul>
    <li>Test-Main</li>
    <li>Test-Main</li>
    <li>Test-Main</li>
    <li>Test-Main</li>
    <li>Test-Main</li>
  </ul>
</div>
<div id="main2">
  Outside Main
</div>

Итак, для вашего случая Это должно быть

$("body").click(function() {
  target = $("#menuscontainer")[0];
  flag = event.path.some(function(el, i, arr) {
    return (el == target)
  });
  if (!flag) {
    // Hide the menus
  }
});
7
ответ дан Dan Philip 14 апр. '17 в 7:27
источник поделиться

Подключить к документу прослушиватель событий щелчка. Внутри прослушивателя событий вы можете посмотреть объект события, в частности, event.target, чтобы увидеть, какой элемент был нажат:

$(document).click(function(e){
    if ($(e.target).closest("#menuscontainer").length == 0) {
        // .closest can help you determine if the element 
        // or one of its ancestors is #menuscontainer
        console.log("hide");
    }
});
6
ответ дан Salman A 03 мая '12 в 12:21
источник поделиться

Если вы используете скрипты для IE и FF 3. *, и вы просто хотите знать, произошел ли щелчок в определенной области окна, вы также можете использовать что-то вроде:

this.outsideElementClick = function(objEvent, objElement){   
var objCurrentElement = objEvent.target || objEvent.srcElement;
var blnInsideX = false;
var blnInsideY = false;

if (objCurrentElement.getBoundingClientRect().left >= objElement.getBoundingClientRect().left && objCurrentElement.getBoundingClientRect().right <= objElement.getBoundingClientRect().right)
    blnInsideX = true;

if (objCurrentElement.getBoundingClientRect().top >= objElement.getBoundingClientRect().top && objCurrentElement.getBoundingClientRect().bottom <= objElement.getBoundingClientRect().bottom)
    blnInsideY = true;

if (blnInsideX && blnInsideY)
    return false;
else
    return true;}
6
ответ дан Erik 14 авг. '09 в 17:08
источник поделиться

Использование:

var go = false;
$(document).click(function(){
    if(go){
        $('#divID').hide();
        go = false;
    }
})

$("#divID").mouseover(function(){
    go = false;
});

$("#divID").mouseout(function (){
    go = true;
});

$("btnID").click( function(){
    if($("#divID:visible").length==1)
        $("#divID").hide(); // Toggle
    $("#divID").show();
});
6
ответ дан webenformasyon 10 янв. '11 в 2:47
источник поделиться
$(document).click(function() {
    $(".overlay-window").hide();
});
$(".overlay-window").click(function() {
    return false;
});

Если вы нажмете на документ, скройте данный элемент, если вы не нажмете на тот же самый элемент.

5
ответ дан Rowan 20 сент. '11 в 21:44
источник поделиться

Перейдите на самый популярный ответ, но добавьте

&& (e.target != $('html').get(0)) // ignore the scrollbar

поэтому щелчок по полосе прокрутки не [скрыть или что-либо еще] вашего целевого элемента.

5
ответ дан bbe 26 июля '15 в 0:33
источник поделиться

Функции:

$(function() {
    $.fn.click_inout = function(clickin_handler, clickout_handler) {
        var item = this;
        var is_me = false;
        item.click(function(event) {
            clickin_handler(event);
            is_me = true;
        });
        $(document).click(function(event) {
            if (is_me) {
                is_me = false;
            } else {
                clickout_handler(event);
            }
        });
        return this;
    }
});

Использование:

this.input = $('<input>')
    .click_inout(
        function(event) { me.ShowTree(event); },
        function() { me.Hide(); }
    )
    .appendTo(this.node);

И функции очень просты:

ShowTree: function(event) {
    this.data_span.show();
}
Hide: function() {
    this.data_span.hide();
}
4
ответ дан Neco 17 июня '10 в 17:58
источник поделиться

В итоге я сделал что-то вроде этого:

$(document).on('click', 'body, #msg_count_results .close',function() {
    $(document).find('#msg_count_results').remove();
});
$(document).on('click','#msg_count_results',function(e) {
    e.preventDefault();
    return false;
});

У меня есть кнопка закрытия в новом контейнере для целей пользовательского интерфейса, ориентированного на конечных пользователей. Мне пришлось использовать return false, чтобы не пройти. Конечно, наличие A HREF там, где можно взять вас где-нибудь, было бы неплохо, иначе вы могли бы назвать некоторые вещи ajax. В любом случае, он работает нормально для меня. Только то, что я хотел.

4
ответ дан Webmaster G 19 нояб. '13 в 4:40
источник поделиться

Я сделал это так: YUI 3:

// Detect the click anywhere other than the overlay element to close it.
Y.one(document).on('click', function (e) {
    if (e.target.ancestor('#overlay') === null && e.target.get('id') != 'show' && overlay.get('visible') == true) {
        overlay.hide();
    }
});

Я проверяю, не является ли предком не контейнер элементов виджета,
если цель не та, которая открывает виджет/элемент,
если виджет/элемент, который я хочу закрыть, уже открыт (не так важно).

4
ответ дан Satya Prakash 06 дек. '11 в 16:42
источник поделиться

Для более удобного использования и более выразительного кода я создал для него плагин jQuery:

$('div.my-element').clickOut(function(target) { 
    //do something here... 
});

Примечание. target - это элемент, который пользователь нажал. Но обратный вызов все еще выполняется в контексте исходного элемента, поэтому вы можете использовать этот, как вы ожидали бы в обратном вызове jQuery.

Plugin:

$.fn.clickOut = function (parent, fn) {
    var context = this;
    fn = (typeof parent === 'function') ? parent : fn;
    parent = (parent instanceof jQuery) ? parent : $(document);

    context.each(function () {
        var that = this;
        parent.on('click', function (e) {
            var clicked = $(e.target);
            if (!clicked.is(that) && !clicked.parents().is(that)) {
                if (typeof fn === 'function') {
                    fn.call(that, clicked);
                }
            }
        });

    });
    return context;
};

По умолчанию прослушиватель событий кликов помещается в документ. Однако, если вы хотите ограничить область прослушивателя событий, вы можете передать объект jQuery, представляющий элемент родительского уровня, который будет основным родителем, по которому будут прослушиваться клики. Это предотвращает ненужные прослушиватели событий уровня документа. Очевидно, что это не сработает, если родительский элемент не является родителем вашего начального элемента.

Используйте так:

$('div.my-element').clickOut($('div.my-parent'), function(target) { 
    //do something here...
});
4
ответ дан Matt Goodwin 21 апр. '16 в 23:04
источник поделиться

Это мое решение этой проблемы:

$(document).ready(function() {
  $('#user-toggle').click(function(e) {
    $('#user-nav').toggle();
    e.stopPropagation();
  });

  $('body').click(function() {
    $('#user-nav').hide(); 
  });

  $('#user-nav').click(function(e){
    e.stopPropagation();
  });
});
4
ответ дан Spencer Fry 21 марта '12 в 19:24
источник поделиться
  • 1
  • 2
  • 3

Другие вопросы по меткам