How do I detect a click outside an element?
I have some HTML menus, which I show completely when a user clicks on the head of these menus. I would like to hide these elements when the user clicks outside the menus' area.
Is something like this possible with jQuery?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
NOTE: Using stopEventPropagation()
is something that should be avoided as it breaks normal event flow in the DOM. See this article for more information. Consider using this method instead.
Attach a click event to the document body which closes the window. Attach a separate click event to the window which stops propagation to the document body.
$(window).click(function() {
//Hide the menus if visible
});
$('#menucontainer').click(function(event){
event.stopPropagation();
});
You can listen for a click event on document
and then make sure #menucontainer
is not an ancestor or the target of the clicked element by using .closest()
.
If it is not, then the clicked element is outside of the #menucontainer
and you can safely hide it.
$(document).click(function(event) {
if(!$(event.target).closest('#menucontainer').length) {
if($('#menucontainer').is(":visible")) {
$('#menucontainer').hide();
}
}
});
Edit – 2017-06-23
You can also clean up after the event listener if you plan to dismiss the menu and want to stop listening for events. This function will clean up only the newly created listener, preserving any other click listeners on document
. With ES2015 syntax:
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)
}
Edit – 2018-03-11
For those who don't want to use jQuery. Here's the above code in plain 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
NOTE: This is based on Alex comment to just use !element.contains(event.target)
instead of the jQuery part.
But element.closest()
is now also available in all major browsers (the W3C version differs a bit from the jQuery one). Polyfills can be found here: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
How to detect a click outside an element?
The reason that this question is so popular and has so many answers is that it is deceptively complex. After almost eight years and dozens of answers, I am genuinely surprised to see how little care has been given to accessibility.
I would like to hide these elements when the user clicks outside the menus' area.
This is a noble cause and is the actual issue. The title of the question—which is what most answers appear to attempt to address—contains an unfortunate red herring.
Hint: it's the word "click"!
You don't actually want to bind click handlers.
If you're binding click handlers to close the dialog, you've already failed. The reason you've failed is that not everyone triggers click
events. Users not using a mouse will be able to escape your dialog (and your pop-up menu is arguably a type of dialog) by pressing Tab, and they then won't be able to read the content behind the dialog without subsequently triggering a click
event.
So let's rephrase the question.
How does one close a dialog when a user is finished with it?
This is the goal. Unfortunately, now we need to bind the userisfinishedwiththedialog
event, and that binding isn't so straightforward.
So how can we detect that a user has finished using a dialog?
focusout
event
A good start is to determine if focus has left the dialog.
Hint: be careful with the blur
event, blur
doesn't propagate if the event was bound to the bubbling phase!
jQuery's focusout
will do just fine. If you can't use jQuery, then you can use blur
during the capturing phase:
element.addEventListener('blur', ..., true);
// use capture: ^^^^
Also, for many dialogs you'll need to allow the container to gain focus. Add tabindex="-1"
to allow the dialog to receive focus dynamically without otherwise interrupting the tabbing flow.
$('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>
链接地址: http://www.djcxy.com/p/272.html
上一篇: 为什么不能在switch语句中声明变量?
下一篇: 如何检测元素外的点击?