防止执行两个指令表达式

时间:2017-01-25 07:29:40

标签: angularjs angularjs-directive angularjs-ng-click

我有这个HTML

<nav ng-init="items = false">
    <ul class="main-items">
        <li><a ng-click="..."></a></li>
        <li><a ng-click="..."></a></li>
        ...
        <li><a ng-click="items = !items">More...</a></li>
    </ul>
    <ul class="more-items" ng-show="items" doc-mousedown="$parent.items = false">
        <li><a ng-click="...">Item 1</a></li>
        <li><a ng-click="...">Item 2</a></li>
        ...
    </ul>
</nav>

这是做什么的:

  1. .main-items始终可见,当点击更多... 时,它会切换more-items的显示。
  2. doc-click是我的自定义简单指令,用于侦听文档 mousedown ,它检查鼠标是否与定义指令的元素外部进行交互并执行提供的表达式。在这种情况下,它会隐藏.more-items
  3. 问题

    单击更多... 链接可以正常显示其他项目,但是当它再次被点击时,此元素位于带有指令的元素之外,因此指令首先触发,然后再触发{strong>更多... 链接上显示ngClick,该链接显示其他项目,而不是隐藏它们...

    我正试图解决这个问题,但我似乎无法解决这个问题。我想在$event.preventDefault()上使用docMousedown,但是moused和click是两个不共享事件对象的事件。 :(

    您如何建议解决此问题?

    工作示例

    DocDetectController.$inject = ["$scope", "$element", "$document"];
    
    function DocDetectController($scope, $element, $document) {
      var el = $element[0];
      var self = this;
      
      $document.on("mousedown.docDetect", function(evt) {
        if (evt.target !== el && !$.contains(el, evt.target)) {
          evt.preventDefault();
          $scope.$apply(self.docDetect);
        }
      });
    }
    
    angular
      .module("Test", [])
      .directive("docDetect", function() {
        return {
          restrict: "A",
          controller: DocDetectController,
          controllerAs: "doc",
          scope: true,
          bindToController: {
            docDetect: "&"
          }
        };
      });
    nav ul {
      display: flex;
      list-style: none;
      margin: 0;
      padding: 0;
      user-select: none;
    }
    nav ul li {
      margin: 0;
      padding: 0;
    }
    nav ul li a {
      text-decoration: none;
      padding: .5rem 1rem;
      background-color: #f4f4f4;
      color: #000;
    }
    nav ul li a:hover {
      background-color: #ddd;
    }
    
    nav.collapsed .more-items {
      display: none;
    }
    
    hr {
      height: 1px;
      border: 0 none;
      background-color: #ccc;
    }
    <section ng-app="Test">
      <nav ng-class="{ collapsed: collapse }" ng-init="collapse = true">
        <ul class="main-items">
          <li><a href="">Link 1</a></li>
          <li><a href="">Link 2</a></li>
          <li><a href="">Link 3</a></li>
          <li><a href="" ng-click="collapse = !collapse">More...</a></li>
        </ul>
        <hr>
        <ul class="more-items" doc-detect="$parent.collapse = true">
          <li><a href="">More 1</a></li>
          <li><a href="">More 2</a></li>
          <li><a href="">More 3</a></li>
          <li><a href="">More 4</a></li>
          <li><a href="">More 5</a></li>
        </ul>
      </nav>
    </section>
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>

2 个答案:

答案 0 :(得分:0)

有一种简单的方法可以检查此解决方案的目标  在你的子事件中,你只需要添加一个检查,你将确保if目标是父元素不会触发任何东西,在这种情况下你需要检查它被触发的元素你可以在你的事件中获得这些细节对象

答案 1 :(得分:0)

最简单的解决方案

是根据$scope.items值更改更多... 的行为的内容。

HTML模板

<nav ng-init="items = false">
    <ul class="main-items">
        <li><a ng-click="..."></a></li>
        <li><a ng-click="..."></a></li>
        ...
        <!-- THIS IS THE CHANGE -->
        <li ng-switch="!!items">
            <a ng-switch-when="false" ng-click="items = !items">More...</a>
            <a ng-switch-when="true" href="">More...</a>
        </li>
    </ul>
    <ul class="more-items" ng-show="items" doc-mousedown="$parent.items = false">
        <li><a ng-click="...">Item 1</a></li>
        <li><a ng-click="...">Item 2</a></li>
        ...
    </ul>
</nav>

&#13;
&#13;
DocDetectController.$inject = ["$scope", "$element", "$document"];

function DocDetectController($scope, $element, $document) {
  var el = $element[0];
  var self = this;
  
  $document.on("mousedown.docDetect", function(evt) {
    if (evt.target !== el && !$.contains(el, evt.target)) {
      evt.preventDefault();
      $scope.$apply(self.docDetect);
    }
  });
}

angular
  .module("Test", [])
  .directive("docDetect", function() {
    return {
      restrict: "A",
      controller: DocDetectController,
      controllerAs: "doc",
      scope: true,
      bindToController: {
        docDetect: "&"
      }
    };
  });
&#13;
nav ul {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  user-select: none;
}
nav ul li {
  margin: 0;
  padding: 0;
}
nav ul li a {
  text-decoration: none;
  padding: .5rem 1rem;
  background-color: #f4f4f4;
  color: #000;
}
nav ul li a:hover {
  background-color: #ddd;
}

nav.collapsed .more-items {
  display: none;
}

hr {
  height: 1px;
  border: 0 none;
  background-color: #ccc;
}
&#13;
<section ng-app="Test">
  <nav ng-class="{ collapsed: collapse }" ng-init="collapse = true">
    <ul class="main-items">
      <li><a href="">Link 1</a></li>
      <li><a href="">Link 2</a></li>
      <li><a href="">Link 3</a></li>
      <li ng-switch="!!collapse">
        <a ng-switch-when="true" href="" ng-click="$parent.collapse = !$parent.collapse">More...</a>
        <a ng-switch-when="false" href="">More...</a>
      </li>
    </ul>
    <hr>
    <ul class="more-items" doc-detect="$parent.collapse = true">
      <li><a href="">More 1</a></li>
      <li><a href="">More 2</a></li>
      <li><a href="">More 3</a></li>
      <li><a href="">More 4</a></li>
      <li><a href="">More 5</a></li>
    </ul>
  </nav>
</section>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
&#13;
&#13;
&#13;