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

这是小提琴演示

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

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

 <div class="feedbackCont" onblur="hidefeedback();">
        <div class="feedbackb" onclick="showfeedback();" ></div>
        <div class="feedbackhide" tabindex="1"> </div>
 </div>

function hidefeedback(){
    $j(".feedbackhide").hide();
}

function showfeedback(){
    $j(".feedbackhide").show();
    $j(".feedbackCont").attr("tabindex",1).focus();
}

这是我想出的最简单的解决方案。

这是我解决这个问题的方法:

$(document).ready(function() {
  $('#user-toggle').click(function(e) {
    $('#user-nav').toggle();
    e.stopPropagation();
  });

  $('body').click(function() {
    $('#user-nav').hide(); 
  });

  $('#user-nav').click(function(e){
    e.stopPropagation();
  });
});

标记为接受答案的答案没有考虑到元素上可以有覆盖,如对话框、弹出窗口、日期选择器等。单击这些按钮不应隐藏元素。

我制作了自己的版本,确实考虑到了这一点。它是作为KnockoutJS绑定创建的,但它可以很容易地仅转换为jQuery。

它通过第一次查询所有具有z索引或绝对位置的可见元素来工作。然后,如果在外部单击,它会根据我想要隐藏的元素来测试这些元素。如果是命中,我会计算一个新的边界矩形,该矩形考虑到覆盖边界。

ko.bindingHandlers.clickedIn = (function () {
    function getBounds(element) {
        var pos = element.offset();
        return {
            x: pos.left,
            x2: pos.left + element.outerWidth(),
            y: pos.top,
            y2: pos.top + element.outerHeight()
        };
    }

    function hitTest(o, l) {
        function getOffset(o) {
            for (var r = { l: o.offsetLeft, t: o.offsetTop, r: o.offsetWidth, b: o.offsetHeight };
                o = o.offsetParent; r.l += o.offsetLeft, r.t += o.offsetTop);
            return r.r += r.l, r.b += r.t, r;
        }

        for (var b, s, r = [], a = getOffset(o), j = isNaN(l.length), i = (j ? l = [l] : l).length; i;
            b = getOffset(l[--i]), (a.l == b.l || (a.l > b.l ? a.l <= b.r : b.l <= a.r))
                && (a.t == b.t || (a.t > b.t ? a.t <= b.b : b.t <= a.b)) && (r[r.length] = l[i]));
        return j ? !!r.length : r;
    }

    return {
        init: function (element, valueAccessor) {
            var target = valueAccessor();
            $(document).click(function (e) {
                if (element._clickedInElementShowing === false && target()) {
                    var $element = $(element);
                    var bounds = getBounds($element);

                    var possibleOverlays = $("[style*=z-index],[style*=absolute]").not(":hidden");
                    $.each(possibleOverlays, function () {
                        if (hitTest(element, this)) {
                            var b = getBounds($(this));
                            bounds.x = Math.min(bounds.x, b.x);
                            bounds.x2 = Math.max(bounds.x2, b.x2);
                            bounds.y = Math.min(bounds.y, b.y);
                            bounds.y2 = Math.max(bounds.y2, b.y2);
                        }
                    });

                    if (e.clientX < bounds.x || e.clientX > bounds.x2 ||
                        e.clientY < bounds.y || e.clientY > bounds.y2) {

                        target(false);
                    }
                }
                element._clickedInElementShowing = false;
            });

            $(element).click(function (e) {
                e.stopPropagation();
            });
        },
        update: function (element, valueAccessor) {
            var showing = ko.utils.unwrapObservable(valueAccessor());
            if (showing) {
                element._clickedInElementShowing = true;
            }
        }
    };
})();