当点击元素外部时触发事件的指令。

29 浏览
0 Comments

当点击元素外部时触发事件的指令。

我知道有很多类似的问题。但是没有人真正解决我的问题。

我正在尝试构建一个指令,该指令将在鼠标点击当前元素之外时执行表达式。

为什么我需要这个功能?我正在构建一个应用程序,在这个应用程序中,有3个下拉菜单,5个下拉列表(类似于chosen)。所有这些都是angular指令。假设这些指令都是不同的。所以我们有8个指令。并且所有它们都需要一个相同的功能:当单击元素之外时,需要隐藏下拉菜单。

对于此,我有两个解决方案,但都有问题:

方法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的示例:点击此处

当您单击第一个下拉菜单时,然后按工作,然后单击第二个输入框,第一个应该隐藏但没有隐藏。

方法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的示例:点击此处

如果页面中只有一个指令,则方法A有效,但在我的应用程序中无效。因为它会阻止冒泡,所以首先当我单击dropdown1时,显示dropdown1,然后单击dropdown2,在单击事件被阻止的情况下,dropdown1仍然在那里显示,即使我单击了dropdown1的外部。

方法B在我现在使用的应用程序中有效。但问题是它会导致性能问题。每次单击应用程序中的任何位置时,都会处理太多的单击事件。在我的当前情况下,有8个单击事件绑定到文档中,因此每次单击都会执行8个函数。这使我的应用程序非常缓慢,特别是在IE8中。

那么有没有更好的解决方案?谢谢

admin 更改状态以发布 2023年5月23日
0
0 Comments

你应该使用ngBlurngFocus来显示或隐藏你的下拉框。当有人点击它时,它会获得焦点,否则它就会变模糊。

此外,请参考这个问题如何在AngularJS中设置输入框的焦点?

编辑:
对于每个指令(下拉菜单或列表,我们称之为Y),当你点击一个元素(我们称之为X)时,你需要显示它,并且在点击Y以外的任何地方(不包括X)时隐藏它。
Y有一个属性isYvisisble。
因此,当有人点击X(ng-click)时,将"isYvisible"设置为真,并将焦点设置在Y上。
当有人点击Y以外的地方(ng-blur)时,你将"isYvisible"设置为假,它就会被隐藏起来。
你需要在两个不同的元素/指令之间分享一个变量("isYvisible"),你可以使用控制器或服务的作用域来实现这一点。还有其他的替代方法,但这超出了本问题的范围。

0
0 Comments

我不会使用event.stopPropagation(),因为它会导致解决方案A中出现的问题。如果可能的话,我也会考虑模糊和聚焦事件。当您的下拉菜单附加在输入框上时,您可以在输入框失去焦点时关闭它。

然而,处理文档上的点击事件也不错,如果您想避免多次处理相同的单击事件,只需在它不再需要时从文档中取消绑定。除了点击下拉列表外,该指令还需要知道它是否启用:

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

使用指令时,只需提供另一个表达式,如下所示:


我没有测试过您的onClick函数。我希望这有所帮助。

0