我知道有很多问题问类似的事情。但是没有人真正解决我的问题。
我正在尝试构建一个指令,当鼠标在当前元素外单击时将执行一个表达式。
为什么我需要这个功能?我正在构建一个应用程序,在这个应用程序中,有 3 个下拉菜单,5 个下拉列表(如选择)。所有这些都是 Angular Directive(指令)。让我们假设所有这些指令都是不同的。所以我们有 8 个指令。并且它们都需要一个相同的功能:当点击元素的外部时,需要隐藏下拉列表。
我有 2 个解决方案,但都有问题:
解决方案 A:
app.directive('clickAnywhereButHere', function($document){
return {
restrict: 'A',
link: function(scope, elem, attr, ctrl) {
elem.bind('click', function(e) {
// this part keeps it from firing the click on the document.
e.stopPropagation();
});
$document.bind('click', function() {
// magic here.
scope.$apply(attr.clickAnywhereButHere);
})
}
}
})
这是解决方案 A 的示例:click here
当您点击第一个下拉菜单,然后工作,然后点击第二个输入时,第一个应该隐藏但不会。
解决方案 B:
app.directive('clickAnywhereButHere', ['$document', function ($document) {
directiveDefinitionObject = {
link: {
pre: function (scope, element, attrs, controller) { },
post: function (scope, element, attrs, controller) {
onClick = function (event) {
var isChild = element.has(event.target).length > 0;
var isSelf = element[0] == event.target;
var isInside = isChild || isSelf;
if (!isInside) {
scope.$apply(attrs.clickAnywhereButHere)
}
}
$document.click(onClick)
}
}
}
return directiveDefinitionObject
}]);
这是解决方案 B 的示例:click here
如果页面中只有一个指令但我的应用程序中没有,则解决方案有效。因为它防止冒泡,所以首先当我点击 dropdown1 时,显示 dropdown1,然后点击 dropdown2,点击事件被阻止,所以即使我在 dropdown1 之外点击,dropdown1 仍然显示在那里。
解决方案 B 在我现在使用的应用程序中运行。但问题是它会导致性能问题。每次单击应用程序中的任何位置时都会处理太多的单击事件。在我目前的例子中,有 8 个点击事件与文档绑定(bind),所以每次点击执行 8 个函数。这导致我的应用程序非常慢,尤其是在 IE8 中。
那么有没有更好的解决办法呢?谢谢
最佳答案
我不会使用 event.stopPropagation(),因为它会导致您在解决方案 A 中看到的那种问题。如果可能,我也会求助于模糊和聚焦事件。当您的下拉列表附加到输入时,您可以在输入失去焦点时将其关闭。
然而,处理文档上的点击事件也不是那么糟糕,所以如果您想避免多次处理同一个点击事件,只需在不再需要时将其与文档解除绑定(bind)即可。除了在下拉列表外单击时要评估的表达式之外,指令还需要知道它是否处于事件状态:
app.directive('clickAnywhereButHere', ['$document', function ($document) {
return {
link: function postLink(scope, element, attrs) {
var onClick = function (event) {
var isChild = $(element).has(event.target).length > 0;
var isSelf = element[0] == event.target;
var isInside = isChild || isSelf;
if (!isInside) {
scope.$apply(attrs.clickAnywhereButHere)
}
}
scope.$watch(attrs.isActive, function(newValue, oldValue) {
if (newValue !== oldValue && newValue == true) {
$document.bind('click', onClick);
}
else if (newValue !== oldValue && newValue == false) {
$document.unbind('click', onClick);
}
});
}
};
}]);
使用指令时,只需提供另一个表达式,如下所示:
<your-dropdown click-anywhere-but-here="close()" is-active="isDropdownOpen()"></your-dropdown>
我没有测试你的 onClick 函数。我认为它按预期工作。希望这会有所帮助。
关于javascript - 在元素外部单击时触发事件的指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20186438/