Javascript 如何检测元素外部的单击?
我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。我想在用户在菜单区域外单击时隐藏这些元素 jQuery可以实现类似的功能吗Javascript 如何检测元素外部的单击?,javascript,jquery,click,Javascript,Jquery,Click,我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。我想在用户在菜单区域外单击时隐藏这些元素 jQuery可以实现类似的功能吗 $("#menuscontainer").clickOutsideThisElement(function() { // Hide the menus }); 检查窗口单击事件目标(它应该传播到窗口,只要它没有在其他任何地方被捕获),并确保它不是任何菜单元素。如果不是,那你就在菜单之外了 或者检查单击的位置,并查看它是否包含在菜单区域内 注
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
检查窗口单击事件目标(它应该传播到窗口,只要它没有在其他任何地方被捕获),并确保它不是任何菜单元素。如果不是,那你就在菜单之外了 或者检查单击的位置,并查看它是否包含在菜单区域内 注意:应该避免使用
stopPropagation
,因为它会破坏DOM中的正常事件流。有关更多信息,请参阅。考虑使用,
将单击事件附加到关闭窗口的文档正文。将单独的单击事件附加到容器,该容器将停止向文档正文的传播
$(窗口)。单击(函数(){
//隐藏菜单(如果可见)
});
$(“#菜单容器”)。单击(函数(事件){
event.stopPropagation();
});
我有一个类似于Eran示例的应用程序,只是在打开菜单时将click事件附加到正文中。。。有点像这样:
$('#menucontainer').click(function(event) {
$('html').one('click',function() {
// Hide the menus
});
event.stopPropagation();
});
var $menuscontainer = ...;
$('#trigger').click(function() {
$menuscontainer.show();
$('body').click(function(event) {
var $target = $(event.target);
if ($target.parents('#menuscontainer').length == 0) {
$menuscontainer.hide();
}
});
});
有关的更多信息此处的其他解决方案不适用于我,因此我不得不使用:
if(!$(event.target).is('#foo'))
{
// hide menu
}
编辑:纯Javascript变体(2021-03-31)
我使用此方法来处理在单击下拉菜单外部时关闭下拉菜单的问题
首先,我为组件的所有元素创建了一个自定义类名。该类名将添加到构成菜单小部件的所有元素中
const className=`dropdown-${Date.now()}-${Math.random()*100}`;
我创建了一个函数来检查单击和单击元素的类名。如果单击的元素不包含我在上面生成的自定义类名,它应该将show
标志设置为false
,菜单将关闭
const onClickOutside=(e)=>{
如果(!e.target.className.includes(className)){
show=false;
}
};
然后,我将单击处理程序附加到窗口对象
//加载小部件时添加
window.addEventListener(“单击”,单击外部);
。。。最后是一些家务活
//销毁小部件时删除侦听器
window.removeEventListener(“单击”,再次单击外部);
如果您正在为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;}
this.outsideElement单击=函数(objEvent,objElement){
var objCurrentElement=objEvent.target | | objEvent.src元素;
var blnisidex=假;
var blnSidey=假;
如果(objCurrentElement.getBoundingClientRect().left>=OBJEElement.getBoundingClientRect().left&&objCurrentElement.getBoundingClientRect().right=OBJEElement.getBoundingClientRect().top&&objCurrentElement.getBoundingClientRect().bottom
对我来说很好。现在有了一个插件:()
当clickoutside处理程序(WLOG)绑定到元素时,会发生以下情况:
- 元素被添加到一个数组中,该数组使用clickoutside处理程序保存所有元素
- ()单击处理程序绑定到文档(如果还没有)
- 在文档中单击时,将为该数组中不等于或不属于单击事件目标父级的元素触发clickoutside事件
- 此外,clickoutside事件的event.target被设置为用户单击的元素(因此您甚至知道用户单击了什么,而不仅仅是他单击了外部)
因此,不会阻止任何事件的传播,并且可以在具有外部处理程序的元素“上方”使用其他单击处理程序。您可以在文档上侦听单击事件,然后使用确保#menucontainer
不是被单击元素的祖先或目标
如果不是,则单击的元素位于#menucontainer
之外,您可以安全地将其隐藏
$(文档)。单击(函数(事件){
var$target=$(event.target);
如果(!$target.closest('#menucontainer')。长度和
$(“#menucontainer”)是(“:可见”)){
$('#menucontainer').hide();
}
});
编辑–2017-06-23
如果您计划关闭菜单并停止侦听事件,也可以在事件侦听器之后进行清理。此函数将仅清理新创建的侦听器,保留文档
上的任何其他单击侦听器。使用ES2015语法:
导出函数HIDEONClickOut(选择器){
const Outside ClickListener=(事件)=>{
const$target=$(event.target);
如果(!$target.closest(selector.length&&$(selector.is)(':visible')){
$(选择器).hide();
removeClickListener();
}
}
常量removeClickListener=()=>{
document.removeEventListener('click',Outside ClickListener)
}
document.addEventListener('click',Outside ClickListener)
}
编辑–2018-03-11
对于那些不想使用jQuery的人,下面是上面的代码,使用的是普通的vanillaJS(ECMAScript 6)
函数隐藏单击外部(元素){
const Outside ClickListener=事件=>{
如果(!element.contains(event.target)&&isVisible(element)){//或使用:event.target.closest(selector)==null
element.style.display='none'
removeClickListener()
}
}
常量removeClickListener=()=>{
document.removeEventListener('click',Outside ClickListener)
}
document.addEventListener('click',Outside ClickListener)
}
const isVisible=elem=>!!elem&&!!(elem.offsetWidth | | elem.offsetHeight | | elem.getclientracts().length)//来源(2018-03-11):https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js
注意:
这是基于Alex注释,仅使用!element.contains(event.tar
...
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);
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()
}
}
var $menuscontainer = ...;
$('#trigger').click(function() {
$menuscontainer.show();
$('body').click(function(event) {
var $target = $(event.target);
if ($target.parents('#menuscontainer').length == 0) {
$menuscontainer.hide();
}
});
});
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();
});
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);
$(document).click(function() {
$(".overlay-window").hide();
});
$(".overlay-window").click(function() {
return false;
});
$('#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);
}
})
});
$(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");
}
});
$('html').click(function (e) {
if (e.target.id == 'YOUR-DIV-ID') {
//do something
} else {
//do something
}
});
$(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");
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();
}
});
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";
}
});
$(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
}
});
(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);
})();
<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>
$(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();
}
});
element.addEventListener('blur', ..., true);
// use capture: ^^^^
window.addEventListener('mouseup', e => {
if (e.target != yourDiv && e.target.parentNode != yourDiv) {
yourDiv.classList.remove('show-menu');
//or yourDiv.style.display = 'none';
}
})
window.addEventListener('mouseup', function (e) {
if (e.target != yourDiv && e.target.parentNode != yourDiv) {
yourDiv.classList.remove('show-menu');
//or yourDiv.style.display = 'none';
}
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;
})
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
}
})
<div class="main-container">
<div> Hello I am the title</div>
<div class="tobehide">I will hide when you click outside of me</div>
</div>