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



14 Answers

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

Если это не так, то элемент #menucontainer находится за пределами #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 

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

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

Question

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

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

$("#menuscontainer").clickOutsideThisElement(function() {
    // Hide the menus
});



We implemented a solution, partly based off a comment from a user above, which works perfectly for us. We use it to hide a search box / results when clicking outside those elements, excluding the element that originally.

// 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');
    }
});

It checks if the search box is already visible first also, and in our case, it's also removing an active class on the hide/show search button.




Функция:

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

And functions are very simple:

ShowTree: function(event) {
    this.data_span.show();
}
Hide: function() {
    this.data_span.hide();
}



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

$(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 если вне события события щелчка.

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




Hook a click event listener on the document. Inside the event listener, you can look at the event object , in particular, the event.target to see what element was clicked:

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



The event has a property called event.path of the element which is a "static ordered list of all its ancestors in tree order" . To check if an event originated from a specific DOM element or one of its children, just check the path for that specific DOM element. It can also be used to check multiple elements by logically OR ing the element check in the some function.

$("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>

So for your case It should be

$("body").click(function() {
  target = $("#menuscontainer")[0];
  flag = event.path.some(function(el, i, arr) {
    return (el == target)
  });
  if (!flag) {
    // Hide the menus
  }
});



$("#menuscontainer").click(function() {
    $(this).focus();
});
$("#menuscontainer").blur(function(){
    $(this).hide();
});

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




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

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



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

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

    })
});



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

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




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

if(!$(event.target).is('#foo'))
{
    // hide menu
}



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

$('html').click(function (e) {
    if (e.target.id == 'YOUR-DIV-ID') {
        //do something
    } else {
        //do something
    }
});



This is my solution to this problem:

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



$(document).click(function() {
    $(".overlay-window").hide();
});
$(".overlay-window").click(function() {
    return false;
});

If you click on the document, hide a given element, unless you click on that same element.




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

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.




Related