0

我发现的当前最佳解决方案:

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;
            }
        }
    };
})();

它通过首先查询具有可见的 z-index 或绝对位置的所有元素来工作。然后,如果单击外部,它会针对我想要隐藏的元素网络对这些元素进行测试。如果它被击中,我会计算一个新的绑定标线,它会考虑覆盖范围。

它不是坚如磐石,但有效。如果您发现上述方法有问题,请随时发表评论

老问题

我正在使用 Knockout 但这通常适用于 DOM/Javascript

如果检测到您在元素外部单击,我试图找到一种可靠的方法。我的代码看起来像这样

    ko.bindingHandlers.clickedIn = {
        init: function (element, valueAccessor) {
            var target = valueAccessor();
            var clickedIn = false;
            ko.utils.registerEventHandler(document, "click", function (e) {
                if (!clickedIn && element._clickedInElementShowing === false) {
                    target(e.target == element);
                }

                clickedIn = false;
                element._clickedInElementShowing = false;
            });

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

它通过监听目标元素和文档的点击来工作。如果您单击文档而不是目标元素,则单击它之外。这有效,但不适用于日期选择器等覆盖项目。这是因为它们不在目标元素内,而是在正文中。我可以解决这个问题吗?是否有更好的方法来确定是否在元素外部单击?

编辑:这种工作,但前提是覆盖小于我要监视的元素

ko.bindingHandlers.clickedIn = {
    init: function (element, valueAccessor) {
        var target = valueAccessor();
        $(document).click(function (e) {
            if (element._clickedInElementShowing === false) {
                var $element = $(element);
                var pos = $element.offset();
                if (e.clientX < pos.left || e.clientX > (pos.left + $element.width()) ||
                    e.clientY < pos.top || e.clientY > (pos.top + $element.height())) {
                    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;
        }
    }
};

我想要一个更坚如磐石的方法

4

2 回答 2

1

我通常是这样解决的:

http://jsfiddle.net/jonigiuro/KLxnV/

$('.container').on('click', function(e) {
    alert('hide the child');
});

$('.child').on('click', function(e) {
    alert('do nothing');
    e.stopPropagation(); //THIS IS THE IMPORTANT PART
});
于 2013-06-18T13:19:56.123 回答
0

我不知道您的叠加项目是如何生成的,但您始终可以检查点击目标是否是您想要限制点击的元素的子元素。

于 2013-06-14T13:30:06.443 回答