P粉2121146612023-08-24 12:19:34
You can listen to the click
event on document and then make sure that the #menucontainer
is not an ancestor or target of the clicked element by using .closest()
.
If not, the clicked element is outside the #menucontainer
and you can safely hide it.
$(document).click(function(event) {
var $target = $(event.target);
if(!$target.closest('#menucontainer').length &&
$('#menucontainer').is(":visible")) {
$('#menucontainer').hide();
}
});
You can also clean up after the event listener if you plan to close the menu and want to stop listening to events. This function will only clean up newly created listeners, leaving any other click listeners on document
. Use ES2015 syntax:
export function hideOnClickOutside(selector) {
const outsideClickListener = (event) => {
const $target = $(event.target);
if (!$target.closest(selector).length && $(selector).is(':visible')) {
$(selector).hide();
removeClickListener();
}
}
const removeClickListener = () => {
document.removeEventListener('click', outsideClickListener);
}
document.addEventListener('click', outsideClickListener);
}
For those who don't want to use jQuery. This is the plain vanillaJS (ECMAScript6) code above.
function hideOnClickOutside(element) {
const outsideClickListener = event => {
if (!element.contains(event.target) && isVisible(element)) { // or use: event.target.closest(selector) === null
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
Notice:
This is based on Alex's comment, just use !element.contains(event.target)
instead of the jQuery part.
But element.closest()
also now works in all major browsers (the W3C version is slightly different from the jQuery version).
Polyfill can be found here: Element.closest()
If you want the user to be able to click and drag inside an element and then release the mouse outside the element without closing the element:
... let lastMouseDownX = 0; let lastMouseDownY = 0; let lastMouseDownWasOutside = false; const mouseDownListener = (event: MouseEvent) => { lastMouseDownX = event.offsetX; lastMouseDownY = event.offsetY; lastMouseDownWasOutside = !$(event.target).closest(element).length; } document.addEventListener('mousedown', mouseDownListener);
In outsideClickListener
:
const outsideClickListener = event => { const deltaX = event.offsetX - lastMouseDownX; const deltaY = event.offsetY - lastMouseDownY; const distSq = (deltaX * deltaX) + (deltaY * deltaY); const isDrag = distSq > 3; const isDragException = isDrag && !lastMouseDownWasOutside; if (!element.contains(event.target) && isVisible(element) && !isDragException) { // or use: event.target.closest(selector) === null element.style.display = 'none'; removeClickListener(); document.removeEventListener('mousedown', mouseDownListener); // Or add this line to removeClickListener() } }
P粉3331862852023-08-24 10:52:59
Attach a click event to the document body of the closed window. Attach a separate click event to the container to stop propagation to the document body.
$(window).click(function() { //Hide the menus if visible }); $('#menucontainer').click(function(event){ event.stopPropagation(); });