Как я могу обнаружить щелчок за пределами элемента?

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

Возможно ли что-то подобное с jQuery?

$("#menuscontainer").clickOutsideThisElement(function() {
    // Hide the menus
});
вопрос задан 30.09.2008
Sergio del Amo
30439 репутация

77 ответов


  • 1637 рейтинг

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

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

    $(window).click(function() {
    //Hide the menus if visible
    });
    
    $('#menucontainer').click(function(event){
        event.stopPropagation();
    });
    
    ответ дан Eran Galperin, с репутацией 73840, 30.09.2008
  • 1163 рейтинг

    Вы можете прослушать событие 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)
    }
    

    Редактировать - 2018-03-11

    Для тех, кто не хочет использовать jQuery. Вот приведенный выше код на простом vanillaJS (ECMAScript6).

    function hideOnClickOutside(element) {
        const outsideClickListener = event => {
            if (!element.contains(event.target)) { // or use: event.target.closest(selector) === null
                if (isVisible(element)) {
                    element.style.display = 'none'
                    removeClickListener()
                }
            }
        }
    
        const removeClickListener = () => {
            document.removeEventListener('click', outsideClickListener)
        }
    
        document.addEventListener('click', outsideClickListener)
    }
    
    const isVisible = elem => !!elem && !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ) // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js 
    

    ПРИМЕЧАНИЕ: Это основано на комментарии Алекса, чтобы просто использовать !element.contains(event.target) вместо части jQuery.

    Но element.closest() теперь также доступен во всех основных браузерах (версия W3C немного отличается от версии jQuery). Полифилы можно найти здесь: https: // developer. Mozilla. org / en-US / docs / Web / API / Element / ближайший

    ответ дан Art, с репутацией 11333, 12.06.2010
  • 203 рейтинг

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

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

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

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

    Подсказка: это слово «щелкни» !

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

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

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

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

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

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

    focusout событие

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

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

    jQuery's 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;
    }
    
    
    Example
    
    Lorem ipsum dolor sit amet.
     

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

    Во-первых, ссылка в диалоговом окне не активна. Попытка щелкнуть по нему или открыть вкладку приведет к закрытию диалогового окна до того, как произойдет взаимодействие. Это связано с тем, что фокусировка внутреннего элемента вызывает событие 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;
    }
    
    
    Example
    
    Lorem ipsum dolor sit amet.
     

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

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

    Это должно выглядеть знакомо
    $('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;
    }
    
    
    Example
    
    Lorem ipsum dolor sit amet.
     

    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;
    }
    
    
    Example
    
    Lorem ipsum dolor sit amet.
     

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

    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;
    }
    
    
    
    lorem ipsum dolor sit amet.

    WAI-ARIA Поддержка ролей и других специальных возможностей

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

    ответ дан zzzzBov, с репутацией 126820, 11.07.2016
  • 129 рейтинг

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

    if(!$(event.target).is('#foo'))
    {
        // hide menu
    }
    
    ответ дан Dennis, с репутацией 1899, 6.07.2009
  • 120 рейтинг

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

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

    Подробнее о функции jQuery one()

    ответ дан Joe Lencioni, с репутацией 6745, 30.09.2008
  • 34 рейтинг
    $("#menuscontainer").click(function() {
        $(this).focus();
    });
    $("#menuscontainer").blur(function(){
        $(this).hide();
    });
    

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

    ответ дан Dennis, с репутацией 1899, 17.11.2009
  • 33 рейтинг

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

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

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

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

    ответ дан Wolfram, с репутацией 7434, 5.04.2010
  • 28 рейтинг

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

    $('html').click(function (e) {
        if (e.target.id == 'YOUR-DIV-ID') {
            //do something
        } else {
            //do something
        }
    });
    
    ответ дан srinath, с репутацией 156, 4.06.2012
  • 28 рейтинг

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

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

    
    
    

    Второй раствор

    
    
    

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

    
    
    
    ответ дан Rameez Rami, с репутацией 1521, 2.11.2015
  • 23 рейтинг

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

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

    1. Если вы прикрепляете обработчик события click к элементу body во время щелчка, обязательно дождитесь второго щелчка, прежде чем закрыть меню и отменить привязку события. В противном случае событие щелчка, открывшее меню, будет пузыриться до слушателя, который должен закрыть меню.
    2. Если вы используете событие. stopPropagation () для события щелчка, никакие другие элементы на вашей странице не могут иметь функцию "щелкнуть в любом месте, чтобы закрыть".
    3. Прикрепление обработчика события click к элементу body на неопределенный срок не является эффективным решением
    4. Сравнение цели события и его родителей с создателем обработчика предполагает, что вы хотите закрыть меню, когда вы щелкаете по нему, когда то, что вы действительно хотите, это закрыть его, когда вы щелкаете в любом месте страницы.
    5. Прослушивание событий в элементе body сделает ваш код более хрупким. Стайлинг так невинен, как это сломало бы его: body { margin-left:auto; margin-right: auto; width:960px;}
    ответ дан 34m0, с репутацией 2867, 18.05.2011
  • 22 рейтинг

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

    $('#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);
            }
    
        })
    });
    
    ответ дан benb, с репутацией 495, 22.12.2011
  • 18 рейтинг

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

    $(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();
        }
    });
    

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

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

    ответ дан Jitendra Damor, с репутацией 477, 15.12.2015
  • 18 рейтинг

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

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

    ответ дан Chris MacDonald, с репутацией 4241, 30.09.2008
  • 16 рейтинг

    Solution1

    Вместо использования события. stopPropagation (), который может иметь некоторые побочные эффекты, просто определите простую переменную flag и добавьте одно условие 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
        }
    });
    
    ответ дан Iman Sedighi, с репутацией 3622, 28.01.2015
  • 14 рейтинг

    Как вариант:

    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.

    ответ дан Bohdan Lyzanets, с репутацией 1119, 24.07.2014
  • 13 рейтинг

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

    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, только если цель (щелчка) не является его дочерней.

    ответ дан Chu Yeow, с репутацией 761, 2.12.2010
  • 12 рейтинг

    Я нашел этот метод в некотором плагине календаря 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);
    
    ответ дан nazar kuliyev, с репутацией 702, 28.07.2011
  • 8 рейтинг

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

    $(document).on("click.menu-outside", function(event){
        // Test if target and it's 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");
    
    ответ дан mems, с репутацией 798, 5.06.2013
  • 8 рейтинг

    Если вы пишете сценарии для 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;}
    
    ответ дан Dennis, с репутацией 1899, 14.08.2009
  • 8 рейтинг

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

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

    (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);
    })();
    Toggle Hidden Div
    

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

    1. Добавьте имя класса hidden к разборному элементу.
    2. После щелчка по документу закройте все скрытые элементы, которые не содержат выбранный элемент и не являются скрытыми
    3. Если выбранный элемент является переключателем, переключите указанный элемент.
    (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);
    })();
    Toggle Hidden Div
    
    Toggle Hidden Div
    
    Toggle Hidden Div
    
    ответ дан Tiny Giant, с репутацией 12755, 19.05.2015
  • 7 рейтинг

    У события есть свойство с именем event. путь к элементу, который представляет собой «статический упорядоченный список всех его предков в древовидной структуре» . Чтобы проверить, произошло ли событие из определенного элемента 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;
    }
    
    
    
    • Test-Main
    • Test-Main
    • Test-Main
    • Test-Main
    • Test-Main
    
    
    Outside Main
     

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

    $("body").click(function() {
      target = $("#menuscontainer")[0];
      flag = event.path.some(function(el, i, arr) {
        return (el == target)
      });
      if (!flag) {
        // Hide the menus
      }
    });
    
    ответ дан Dan Philip, с репутацией 3105, 14.04.2017
  • 6 рейтинг

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

    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();
    });
    
    ответ дан webenformasyon, с репутацией 125, 9.01.2011
  • 6 рейтинг

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

    $(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");
        }
    });
    
    ответ дан Salman A, с репутацией 165526, 3.05.2012
  • 5 рейтинг
    $(document).click(function() {
        $(".overlay-window").hide();
    });
    $(".overlay-window").click(function() {
        return false;
    });
    

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

    ответ дан Rowan, с репутацией 71, 20.09.2011
  • 5 рейтинг

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

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

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

    Плагин:

    $.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...
    });
    
    ответ дан Matt Goodwin, с репутацией 563, 21.04.2016
  • 5 рейтинг

    Upvote для самого популярного ответа, но добавьте

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

    Итак, нажатие на полосу прокрутки не [скрывает или что-то еще] ваш целевой элемент.

    ответ дан bbe, с репутацией 210, 25.07.2015
  • 4 рейтинг

    Функция:

    $(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 = $('')
        .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();
    }
    
    ответ дан Neco, с репутацией 31, 17.06.2010
  • 4 рейтинг

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

    $(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();
      });
    });
    
    ответ дан Spencer Fry, с репутацией 119, 21.03.2012
  • 4 рейтинг

    Я закончил делать что-то вроде этого:

    $(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. В любом случае, у меня все в порядке. Как раз то, что я хотел.

    ответ дан Webmaster G, с репутацией 311, 19.11.2013
  • 4 рейтинг

    Я сделал это в гг. 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();
        }
    });
    

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

    ответ дан Satya Prakash, с репутацией 1320, 6.12.2011
  • 4 рейтинг

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

    // HIDE SEARCH BOX IF CLICKING OUTSIDE
    $(document).click(function(event){ 
        // IF NOT CLICKING THE SEARCH BOX OR ITS CONTENTS OR SEARCH ICON 
        if ($("#search-holder").is(":visible") && !$(event.target).is("#search-holder *, #search")) {
            $("#search-holder").fadeOut('fast');
            $("#search").removeClass('active');
        }
    });
    

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

    ответ дан Scott Richardson, с репутацией 72, 8.07.2015
  • 3 рейтинг

    Это должно работать:

    $('body').click(function (event) {
        var obj = $(event.target);
        obj = obj['context']; // context : clicked element inside body
        if ($(obj).attr('id') != "menuscontainer" && $('#menuscontainer').is(':visible') == true) {
            //hide menu
        }
    });
    
    ответ дан Bilal Berjawi, с репутацией 11, 12.01.2013
  • 3 рейтинг

    Решения здесь работают нормально , когда нужно управлять только одним элементом . Однако, если есть несколько элементов, проблема намного сложнее. Трюки с е. stopPropagation () и все остальные не будут работать.

    Я придумала решение 3894676001 , и, возможно, это не так просто, но лучше, чем ничего. Посмотрите:

    $view.on("click", function(e) {
    
        if(model.isActivated()) return;
    
            var watchUnclick = function() {
                rootView.one("mouseleave", function() {
                    $(document).one("click", function() {
                        model.deactivate();
                    });
                    rootView.one("mouseenter", function() {
                        watchUnclick();
                    });
                });
            };
            watchUnclick();
            model.activate();
        });
    
    ответ дан kboom, с репутацией 796, 31.05.2013
  • 2 рейтинг

    Вот мой код:

    // Listen to every click
    $('html').click(function(event) {
        if ( $('#mypopupmenu').is(':visible') ) {
            if (event.target.id != 'click_this_to_show_mypopupmenu') {
                $('#mypopupmenu').hide();
            }
        }
    });
    
    // Listen to selector's clicks
    $('#click_this_to_show_mypopupmenu').click(function() {
    
      // If the menu is visible, and you clicked the selector again we need to hide
      if ( $('#mypopupmenu').is(':visible') {
          $('#mypopupmenu').hide();
          return true;
      }
    
      // Else we need to show the popup menu
      $('#mypopupmenu').show();
    });
    
    ответ дан netdjw, с репутацией 1161, 6.03.2012
  • 2 рейтинг

    Я использовал приведенный ниже скрипт и сделал с помощью jQuery.

    jQuery(document).click(function(e) {
        var target = e.target; //target div recorded
        if (!jQuery(target).is('#tobehide') ) {
            jQuery(this).fadeOut(); //if the click element is not the above id will hide
        }
    })
    

    Ниже найдите HTML-код

    Hello I am the title
    I will hide when you click outside of me
    
    

    Вы можете прочитать учебник здесь

    ответ дан Rinto George, с репутацией 17634, 14.01.2018
  • 2 рейтинг

    Еще одно решение здесь:

    http: // jsfiddle. net / zR76D /

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

    Open / Close Menu
    
    
    
    
    

    Плагин:

    (function($) {
        var clickOutsideElements = [];
        var clickListener = false;
    
        $.fn.clickOutside = function(options, ignoreFirstClick) {
            var that = this;
            if (ignoreFirstClick == null) ignoreFirstClick = true;
    
            if (options != "disable") {
                for (var i in clickOutsideElements) {
                    if (clickOutsideElements[i].element[0] == $(this)[0]) return this;
                }
    
                clickOutsideElements.push({ element : this, clickDetected : ignoreFirstClick, fnc : (typeof(options) != "function") ? function() {} : options });
    
                $(this).on("click.clickOutside", function(event) {
                    for (var i in clickOutsideElements) {
                        if (clickOutsideElements[i].element[0] == $(this)[0]) {
                            clickOutsideElements[i].clickDetected = true;
                        }
                    }
                });
    
                if (!clickListener) {
                    if (options != null && typeof(options) == "function") {
                        $('html').click(function() {
                            for (var i in clickOutsideElements) {
                                if (!clickOutsideElements[i].clickDetected) {
                                    clickOutsideElements[i].fnc.call(that);
                                }
                                if (clickOutsideElements[i] != null) clickOutsideElements[i].clickDetected = false;
                            }
                        });
                        clickListener = true;
                    }
                }
            }
            else {
                $(this).off("click.clickoutside");
                for (var i = 0; i < clickOutsideElements.length; ++i) {
                    if (clickOutsideElements[i].element[0] == $(this)[0]) {
                        clickOutsideElements.splice(i, 1);
                    }
                }
            }
    
            return this;
        }
    })(jQuery);
    
    ответ дан teynon, с репутацией 3769, 30.05.2013
  • 2 рейтинг

    Вот что я делаю, чтобы решить проблему.

    $(window).click(function (event) {
        //To improve performance add a checklike 
        //if(myElement.isClosed) return;
        var isClickedElementChildOfMyBox = isChildOfElement(event,'#id-of-my-element');
    
        if (isClickedElementChildOfMyBox)
            return;
    
        //your code to hide the element 
    });
    
    var isChildOfElement = function (event, selector) {
        if (event.originalEvent.path) {
            return event.originalEvent.path[0].closest(selector) !== null;
        }
    
        return event.originalEvent.originalTarget.closest(selector) !== null;
    }
    
    ответ дан Fabian, с репутацией 51, 27.07.2017
  • 2 рейтинг

    Вот простое решение с помощью чистого JavaScript. Это современный с ES6 :

    var isMenuClick = false;
    var menu = document.getElementById('menuscontainer');
    document.addEventListener('click',()=>{
        if(!isMenuClick){
           //Hide the menu here
        }
        //Reset isMenuClick 
        isMenuClick = false;
    })
    menu.addEventListener('click',()=>{
        isMenuClick = true;
    })
    
    ответ дан Duannx, с репутацией 3038, 3.11.2017
  • 2 рейтинг

    Это прекрасно работало со временем для меня:

    $('body').click(function() {
        // Hide the menus if visible.
    });
    
    ответ дан govind, с репутацией 31, 2.06.2010
  • 2 рейтинг

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

    Я сделал свою собственную версию, которая учитывает это. Он создан как привязка KnockoutJS , но его легко конвертировать в jQuery-only.

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

    ko.bindingHandlers.clickedIn = (function () {
        function getBounds(element) {
            var pos = element.offset();
            return {
                x: pos.left,
                x2: pos.left + element.outerWidth(),
                y: pos.top,
                y2: pos.top + element.outerHeight()
            };
        }
    
        function hitTest(o, l) {
            function getOffset(o) {
                for (var r = { l: o.offsetLeft, t: o.offsetTop, r: o.offsetWidth, b: o.offsetHeight };
                    o = o.offsetParent; r.l += o.offsetLeft, r.t += o.offsetTop);
                return r.r += r.l, r.b += r.t, r;
            }
    
            for (var b, s, r = [], a = getOffset(o), j = isNaN(l.length), i = (j ? l = [l] : l).length; i;
                b = getOffset(l[--i]), (a.l == b.l || (a.l > b.l ? a.l <= b.r : b.l <= a.r))
                    && (a.t == b.t || (a.t > b.t ? a.t <= b.b : b.t <= a.b)) && (r[r.length] = l[i]));
            return j ? !!r.length : r;
        }
    
        return {
            init: function (element, valueAccessor) {
                var target = valueAccessor();
                $(document).click(function (e) {
                    if (element._clickedInElementShowing === false && target()) {
                        var $element = $(element);
                        var bounds = getBounds($element);
    
                        var possibleOverlays = $("[style*=z-index],[style*=absolute]").not(":hidden");
                        $.each(possibleOverlays, function () {
                            if (hitTest(element, this)) {
                                var b = getBounds($(this));
                                bounds.x = Math.min(bounds.x, b.x);
                                bounds.x2 = Math.max(bounds.x2, b.x2);
                                bounds.y = Math.min(bounds.y, b.y);
                                bounds.y2 = Math.max(bounds.y2, b.y2);
                            }
                        });
    
                        if (e.clientX < bounds.x || e.clientX > bounds.x2 ||
                            e.clientY < bounds.y || e.clientY > bounds.y2) {
    
                            target(false);
                        }
                    }
                    element._clickedInElementShowing = false;
                });
    
                $(element).click(function (e) {
                    e.stopPropagation();
                });
            },
            update: function (element, valueAccessor) {
                var showing = ko.utils.unwrapObservable(valueAccessor());
                if (showing) {
                    element._clickedInElementShowing = true;
                }
            }
        };
    })();
    
    ответ дан Anders, с репутацией 12508, 18.06.2013
  • 2 рейтинг

    Если честно, мне не понравилось ни одно из предыдущих решений.

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

    Однако у вас возникнут некоторые проблемы: вы никогда не сможете отсоединить его, и у вас не может быть внешней кнопки, чтобы открыть / закрыть этот элемент.

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

    Toggle the menu
    I should be toggled when the above menu is clicked, and hidden when user clicks outside.
     
    
    
    
    ответ дан Alexandre T., с репутацией 1163, 25.11.2012
  • 2 рейтинг

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

    Затем, когда меню закрыто, удалите привязку.

    Использование. stopPropagation для предотвращения влияния события на любую часть менюконтейнера.

    $("*").not($("#menuscontainer")).bind("click.OutsideMenus", function ()
    {
        // hide the menus
    
        //then remove all of the handlers
        $("*").unbind(".OutsideMenus");
    });
    
    $("#menuscontainer").bind("click.OutsideMenus", function (event) 
    {
        event.stopPropagation(); 
    });
    
    ответ дан maday, с репутацией 1, 31.05.2013
  • 2 рейтинг
    jQuery().ready(function(){
        $('#nav').click(function (event) {
            $(this).addClass('activ');
            event.stopPropagation();
        });
    
        $('html').click(function () {
            if( $('#nav').hasClass('activ') ){
                $('#nav').removeClass('activ');
            }
        });
    });
    
    ответ дан Toogy, с репутацией 11, 9.04.2012
  • 2 рейтинг

    Для сенсорных устройств, таких как 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();
        }
    });
    
    ответ дан Manish Shrivastava, с репутацией 17323, 8.10.2014
  • 1 рейтинг

    Я удивлен, что на самом деле никто не признал событие focusout:

    var button = document.getElementById('button');
    button.addEventListener('click', function(e){
      e.target.style.backgroundColor = 'green';
    });
    button.addEventListener('focusout', function(e){
      e.target.style.backgroundColor = '';
    });
    
    
    
    
    
    
    
    
    ответ дан Jovanni G, с репутацией 95, 12.02.2018
  • 1 рейтинг

    Это работает для меня

    $("body").mouseup(function(e) {
        var subject = $(".main-menu");
        if(e.target.id != subject.attr('id') && !subject.has(e.target).length) {
            $('.sub-menu').hide();
        }
    });
    
    ответ дан hienbt88, с репутацией 836, 13.09.2017
  • 1 рейтинг
    $(document).on("click",function (event)   
     {   
         console.log(event);
       if ($(event.target).closest('.element').length == 0)
         {
        //your code here
          if ($(".element").hasClass("active"))
          {
            $(".element").removeClass("active");
          }
         }
     });
    

    Попробуйте эту кодировку для получения решения.

    ответ дан karthikeyan ganesan, с репутацией 578, 24.02.2017
  • 1 рейтинг

    Если кому-то интересно, вот решение javascript (es6):

    window.addEventListener('mouseup', e => {
            if (e.target != yourDiv && e.target.parentNode != yourDiv) {
                yourDiv.classList.remove('show-menu');
                //or yourDiv.style.display = 'none';
            }
        })
    

    и es5, на всякий случай:

    window.addEventListener('mouseup', function (e) {
    if (e.target != yourDiv && e.target.parentNode != yourDiv) {
        yourDiv.classList.remove('show-menu'); 
        //or yourDiv.style.display = 'none';
    }
    

    });

    ответ дан Walt, с репутацией 62, 18.07.2017
  • 1 рейтинг

    Чтобы скрыть fileTreeClass, если щелкнуть за его пределами

     jQuery(document).mouseup(function (e) {
                var container = $(".fileTreeClass");
                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();
                }
            });
    
    ответ дан Thamaraiselvam, с репутацией 4142, 17.08.2016
  • 1 рейтинг

    Я просто хочу, чтобы ответ @Pistos был более очевидным, поскольку он скрыт в комментариях.

    Это решение отлично сработало для меня. Обычный JS:

    var elementToToggle = $('.some-element');
    $(document).click( function(event) {
      if( $(event.target).closest(elementToToggle).length === 0 ) {
        elementToToggle.hide();
      }
    });
    

    в CoffeeScript:

    elementToToggle = $('.some-element')
    $(document).click (event) ->
      if $(event.target).closest(elementToToggle).length == 0
        elementToToggle.hide()
    
    ответ дан DaniG2k, с репутацией 1982, 7.03.2018