我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。当用户在菜单区域外单击时,我希望隐藏这些元素。

jQuery是否可以实现这样的功能?

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

当前回答

作为Art这个伟大答案的包装,并使用OP最初要求的语法,这里有一个jQuery扩展,它可以记录在集合元素之外是否发生了单击。

$.fn.clickOutsideThisElement = function (callback) {
    return this.each(function () {
        var self = this;
        $(document).click(function (e) {
            if (!$(e.target).closest(self).length) {
                callback.call(self, e)
            }
        })
    });
};

然后你可以这样打电话:

$("#menuscontainer").clickOutsideThisElement(function() {
    // handle menu toggle
});

这是小提琴演示

其他回答

所有这些答案都解决了这个问题,但我想提供一个完全符合需要的moders es6解决方案。我只是希望让大家对这个可运行的演示感到满意。

window.clickOutSide=(元素,单击外部,单击内部)=>{document.addEventListener('click',(event)=>{if(!element.contains(event.target)){if(单击类型内部==“函数”){单击外侧();}}其他{if(单击类型内部==“函数”){单击内侧();}}});};window.clickOutSide(document.querySelector('.block'),()=>警报('clicked outside');.块{宽度:400px;高度:400px;背景色:红色;}<div class=“block”></div>

解决方案1

不要使用event.stopPropagation(),因为它会产生一些副作用,只需定义一个简单的标志变量并添加一个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";
    }
});

解决方案2

只有一个简单的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
    }
});

这里的其他解决方案不适合我,所以我不得不使用:

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

编辑:普通Javascript变体(2021-03-31)

我使用这个方法来处理在单击下拉菜单外部时关闭下拉菜单的问题。

首先,我为组件的所有元素创建了一个自定义类名。这个类名将被添加到组成菜单小部件的所有元素中。

const className = `dropdown-${Date.now()}-${Math.random() * 100}`;

我创建了一个函数来检查单击和单击元素的类名。如果clicked元素不包含我上面生成的自定义类名,它应该将show标志设置为false,菜单将关闭。

const onClickOutside = (e) => {
  if (!e.target.className.includes(className)) {
    show = false;
  }
};

然后,我将单击处理程序附加到窗口对象。

// add when widget loads
window.addEventListener("click", onClickOutside);

……最后还有一些家政服务

// remove listener when destroying the widget
window.removeEventListener("click", onClickOutside);

我在一些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);

检查窗口单击事件目标(它应该传播到窗口,只要它没有在其他地方被捕获),并确保它不是任何菜单元素。如果不是,那么你就在菜单之外。

或者检查单击的位置,看看它是否包含在菜单区域中。