如何在Angular中有效地检测元素点击

How to detect element click efficiently in Angular?

本文关键字:检测 元素 有效地 Angular      更新时间:2023-09-26

这是我的指令的链接函数

    function linkFunc(scope, element, attr){
        // Detect Element Click Logic
        scope.myCtrl.clickedElsewhere = {value: true};
        $document.on('click', function(){
            scope.myCtrl.clickedElsewhere.value = true;
            scope.$apply();
        });
        element.on('click', function(){
            event.stopPropagation();
            scope.myCtrl.clickedElsewhere.value = false;
            scope.$apply();
        });
        // End Detect Element Click Logic
    }

正如我们所看到的,我们使用了$document.on()scope.apply,这意味着每次点击文档中的任何位置,我们都会触发一个摘要循环。如果我们有很多$watch触发器,这可能会导致网页速度减慢。尽管这种实现并不完全有效,但我想不出其他方法来检测元素上的点击和元素外的点击,以扩展和收缩我的元素。

有人能提供一些见解吗?

感谢

在文档点击处理程序中调用$apply()之前检查scope.myCtrl.clickedElsewhere.value会更有效率

$document.on('click', function(){
   if(!scope.myCtrl.clickedElsewhere.value){
       scope.myCtrl.clickedElsewhere.value = true;
       scope.$apply();
   }
});

当状态没有变化时,这将防止不必要的消化。


你也可以删除这个点击监听器,并在点击元素时重新应用它:

function docHandler() {
  if (!scope.myCtrl.clickedElsewhere.value) {
    scope.myCtrl.clickedElsewhere.value = true;
    scope.$apply();
    $document.off('click');//remove event listener completely
  }
}
element.on('click', function() {
  event.stopPropagation();
  scope.myCtrl.clickedElsewhere.value = false;
  scope.$apply();
  $document.on('click', docHandler);// add document listener
});

您只需创建一个点击关闭指令

myApp.directive('clickOff', function($parse, $document) {
  var dir = {
    compile: function($element, attr) {
      // Parse the expression to be executed
      // whenever someone clicks _off_ this element.
      var fn = $parse(attr["clickOff"]);
      return function(scope, element, attr) {
        // add a click handler to the element that
        // stops the event propagation.
        element.bind("click", function(event) {
          event.stopPropagation();
        });
        angular.element($document[0].body).bind("click",function(event) {
            scope.$apply(function() {
                fn(scope, {$event:event});
            });
        });
      };
    }
  };
  return dir;
});

用法:

<div ng-app="myApp">
  <button ng-click="show=true;" click-off="show=false;">
      Click Me
  </button>
  <div class="message" ng-show="show" ng-init="show = false">
    You clicked on the button. Now click anywhere else...
  </div>
</div>

示例:https://jsfiddle.net/oytdwyxj/

您可以创建两个指令,它们之间具有父/子关系。

看看我创建的手风琴指令,我相信这就是你需要的,以了解你的情况。

指令:

app.directive("accordion", function () {
    return {
        template: "<div ng-transclude></div>",
        restrict: "E",
        scope: {
            closeall: "@"
        },
        transclude: true,
        replace: true,
        controller: function ($scope, $element, $attrs) {
            var itensScope = [];
            var addItemScope = function (scope) {
                itensScope.push(scope);
            };
            var closeItens = function () {
                if ($scope.closeall == "false") return;
                angular.forEach(itensScope, function (scope) {
                    scope.showItem = false;
                });
            }
            return {
                addItemScope: addItemScope,
                closeItens: closeItens
            };
        }
    };
});
app.directive("accordionItem", function () {
    return {
        template: "<div><div class='item' ng-class='{itemClose: !showItem}'>{{title}}</div><div class='itemInformation' ng-show='showItem' ng-transclude></div></div>",
        restrict: "E",
        transclude: true,
        replace: true,
        scope: {
            title: "@"
        },
        require: "^accordion",
        link: function (scope, element, attrs, ctrl, transcludeFn) {
            ctrl.addItemScope(scope);
            element.bind("click", function () {
                ctrl.closeItens();
                scope.$apply(function () { 
                    scope.showItem = !scope.showItem; 
                });
            });
        }
    };
});

用法:

<accordion closeall="true">
        <accordion-item title="A">
            <p>
                A
            </p>
        </accordion-item>
        <accordion-item title="B">
            <p>
                B
            </p>
        </accordion-item>
</accordion>

我不久前创建了这个例子,它在我的GitHub中可用:https://github.com/rodrigobranas/branas-angular-ui