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

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

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

当前回答

对于那些希望将一个简短的解决方案集成到JS代码中的人来说——一个没有JQuery的小型库:

用法:

// demo code
var htmlElem = document.getElementById('my-element')
function doSomething(){ console.log('outside click') }

// use the lib
var removeListener = new elemOutsideClickListener(htmlElem, doSomething);

// deregister on your wished event
$scope.$on('$destroy', removeListener);

下面是库:


function elemOutsideClickListener (element, outsideClickFunc, insideClickFunc) {
   function onClickOutside (e) {
      var targetEl = e.target; // clicked element
      do {
         // click inside
         if (targetEl === element) {
            if (insideClickFunc) insideClickFunc();
            return;

         // Go up the DOM
         } else {
            targetEl = targetEl.parentNode;
         }
      } while (targetEl);

      // click outside
      if (!targetEl && outsideClickFunc) outsideClickFunc();
   }

   window.addEventListener('click', onClickOutside);

   return function () {
      window.removeEventListener('click', onClickOutside);
   };
}

我从这里获取代码并将其放在函数中:https://www.w3docs.com/snippets/javascript/how-to-detect-a-click-outside-an-element.html

其他回答

当只有一个元素需要管理时,这里的解决方案工作得很好。然而,如果有多个元素,问题就复杂得多。e.stopPropagation()的技巧和其他所有技巧都不起作用。

我想出了一个解决方案,也许不是那么容易,但总比什么都没有好。看看:

$view.on("click", function(e) {

    if(model.isActivated()) return;

        var watchUnclick = function() {
            rootView.one("mouseleave", function() {
                $(document).one("click", function() {
                    model.deactivate();
                });
                rootView.one("mouseenter", function() {
                    watchUnclick();
                });
            });
        };
        watchUnclick();
        model.activate();
    });

这是一个更通用的解决方案,它允许监视多个元素,并动态地从队列中添加和删除元素。

它保存一个全局队列(autoCloseQueue)——一个对象容器,用于在外部单击时应关闭的元素。

每个队列对象键都应该是DOM元素id,值应该是一个具有2个回调函数的对象:

 {onPress: someCallbackFunction, onOutsidePress: anotherCallbackFunction}

将其放入文档就绪回调中:

window.autoCloseQueue = {}  

$(document).click(function(event) {
    for (id in autoCloseQueue){
        var element = autoCloseQueue[id];
        if ( ($(e.target).parents('#' + id).length) > 0) { // This is a click on the element (or its child element)
            console.log('This is a click on an element (or its child element) with  id: ' + id);
            if (typeof element.onPress == 'function') element.onPress(event, id);
        } else { //This is a click outside the element
            console.log('This is a click outside the element with id: ' + id);
            if (typeof element.onOutsidePress == 'function') element.onOutsidePress(event, id); //call the outside callback
            delete autoCloseQueue[id]; //remove the element from the queue
        }
    }
});

然后,当创建id为“menuscontainer”的DOM元素时,只需将此对象添加到队列:

window.autoCloseQueue['menuscontainer'] = {onOutsidePress: clickOutsideThisElement}
$("#menuscontainer").click(function() {
    $(this).focus();
});
$("#menuscontainer").blur(function(){
    $(this).hide();
});

对我来说很好。

这对我来说非常及时:

$('body').click(function() {
    // Hide the menus if visible.
});

使用流中断、模糊/聚焦事件或任何其他棘手的技术,只需将事件流与元素的亲属关系匹配即可:

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