避免在指令

时间:2016-03-30 12:22:29

标签: javascript angularjs javascript-events stoppropagation event-propagation

我有一个工具提示指令,可以在点击时打开/关闭,并在任意点击时关闭。由于angular-translate不允许更改元素本身的内容,因此我会附加指令的元素。

该指令看起来有点像这样(请注意这是一个简化版本):

{
    restrict: 'A',
    scope: {},
    compile: function(element)
    {
        element.after('<div class="toggle"></div>
            <div class="message" ng-show="active"></div>');
    },
    link: function(scope, element)
    {
        angular.element(element.siblings('toggle')).click(function()
        {
            scope.$apply(function()
            {
                scope.active = !scope.active;
            }
        });
        angular.element(document).click(function()
        {
            scope.$apply(function()
            {
                scope.active = false;
            }
        });
    } 
}

问题在于元素上的click事件被触发(scope.active = true),然后传播到文档,而它立即关闭。

但是,如果我停止传播,它在大多数情况下都能正常工作,有一种情况就是当我在我的页面上有多个指令实例并且一个接一个地点击时(第一个打开的应该关闭并且另一个应该打开,但是由于传播被停止,另一个实例的document.click事件不会被触发。

编辑: This fiddle演示了此问题。如果您单击绿色框并再次单击它,它会工作,如果您单击绿色框,然后单击它工作的背景,如果您单击绿色框,然后单击另一个绿色框但是两个都打开,但第一个应该关闭。
如果您删除event.stopPropagation() line 20上的/core-service=management/management-interface=http-interface/:write-attribute(name=console-enabled,value=true) 该提示根本没有显示,因为首先触发该框的点击,会显示提示,但在进一步的事件传播后,点击背景会触发好吧,然后立即关闭它。

如果对我的问题有更好的解决方案,我也会感激

1 个答案:

答案 0 :(得分:0)

这是可以帮助您的解决方案之一。

jsfiddle上的实例。

angular.module('app', [])
  .controller('testCtrl', ['$scope',
    function($scope) {
      var self = this;
    }
  ])
  .directive('hintDirective', ['$compile',
    function($compile) {
      var directiveHint = [];
      return {
        restrict: 'A',
        transclude: true,
        scope: {},
        template: '<ng-transclude></ng-transclude><span ng-click="toggle($event)" class="toggle"></span><div class="message" ng-show="active">Hint Message</div>',
        link: function(scope, element) {
          scope.active = false;
          directiveHint.push(scope);
          var span = element.find('span')[1];
          scope.toggle = function($ev) {
            scope.active = !scope.active;
            closeOther(scope);
            $ev.stopPropagation();
          }

          function closeOther(scope) {
            angular.forEach(directiveHint, function(sc) {
              if (sc != scope) {
                closeActive(sc)
              }
            });
          }

          function closeAll() {
            angular.forEach(directiveHint, function(sc) {
              closeActive(sc)
            });
          }

          function closeActive(sc) {
            if (sc.active)
              sc.active = false;
          }

          function documentClick(event) {
            scope.$apply(function() {
              closeAll();
            });
          }
          var $body = angular.element(document.body);
          if (!$body.hasClass('hint-directive-click')) {
            angular.element(document).bind('click', documentClick);
            $body.addClass('hint-directive-click');
          }

          scope.$on('$destroy', function() {
            angular.forEach(directiveHint, function(sc, i) {
              if (sc == scope)
                directiveHint.splice(i);
            });
          })
        }
      }
    }
  ]);
html,
body {
  width: 100%;
  height: 100%;
}
.split {
  float: left;
  width: 50%;
  height: 100%;
}
.toggle {
  display: inline-block;
  width: 1em;
  height: 1em;
  background-color: green;
}
p {
  float: left;
}
.message {
  background-color: grey;
  width: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="app">
  <div class="split">
    <br>
    <br>
    <br>
    <br>
    <br>
    <p hint-directive>
      Text1
    </p>
  </div>
  <div class="split">
    <br>
    <br>
    <br>
    <br>
    <br>
    <p hint-directive>
      Text2
    </p>
    <label>
      <input type="checkbox" ng-model="text3Enable">Enable text3</label>
    <p hint-directive ng-if="text3Enable">
      Text3
    </p>
  </div>
</div>