【问题标题】:AngularJS : Climb up the scope tree in an ng-repeatAngularJS:在 ng-repeat 中爬上作用域树
【发布时间】:2014-03-11 00:51:47
【问题描述】:

我想构建一个弹出树形菜单,在悬停时向元素添加 active 类,并在其任何兄弟元素悬停时将其删除。

这样,当用户将鼠标移开时,菜单将保持打开状态。

弹出菜单是递归的,因为它可以是任意数量的深度。

为了从兄弟姐妹中删除一个班级,我必须了解他们的父母或兄弟姐妹的身份。更愿意使用数据结构来执行此操作,但如果需要,将使用 DOM 遍历。

我试过了:

  • 在悬停处理程序中使用 scope.$parent(但处理程序知道的范围是指令范围,而不是 ng-repeat 范围)
  • 将事件传递给悬停处理程序并调用 $(evt).siblings()(但角度大叫,说我无法从表达式访问 DOM)
  • 在本地 ng-repeat 范围内设置 .parent 属性(但事件处理程序无权访问模板继承的这些值)
  • 使用递归指令,因此树中的每一片叶子都是另一个指令。这会使浏览器爆炸。 (我认为是因为它会在寻找循环中的退出条件之前尝试编译指令)
  • 为树中的每个叶子添加一个控制器。这会使作用域树变大,并且不提供访问同级的干净方法。虽然它是功能性的。请参阅下面的答案。

我不知道如何在 Angular 中做到这一点。在 jQuery 中执行此操作非常简单:$(e.target).siblings().removeClass('active')。我怎样才能完成这项工作?

我制作了一个 Plunker 来演示在递归 ng-repeat 中访问同级的问题:http://plnkr.co/edit/vBYYt6sTvWKN9TXz9SC5?p=preview

【问题讨论】:

  • 您查看过Creating Directives that Communicate 的文档吗?
  • 是的。您是否建议我为树中的每个节点创建一个指令?可能是一个想法......
  • 你试过 CSS :hover 伪类吗?
  • 是的,我认为将逻辑放在指令中更有意义
  • @Stewie :hover 是这些通常的做法,但 UI 要求是菜单在离开后保持打开状态。

标签: angularjs angularjs-directive angularjs-ng-repeat


【解决方案1】:

一个很好的解决方案使用一个变量来跟踪树的每个级别的活动叶。在此方法中,声明父范围内的变量,并分配叶范围内的变量。在任何给定时间只有一个兄弟姐妹处于活动状态:ng-class="{active: branch.name == activeLeaf}"

Plunkr 由Cam[tab]#angularjs 撰写:http://plnkr.co/edit/u5EiP2DmQtBROxL7Qq53?p=preview

您可以在每个 ng-repeat 上方使用控制器来声明作用域,但这会增加很多作用域层。您可以使用嵌套指令来包含范围,但这些指令会无限递归。上面链接的 Cam 的解决方案包括 ng-include 中的嵌套指令,它生成了一个很好的精简范围树并避免了无限递归。

【讨论】:

    【解决方案2】:

    您可以在使用 ng-repeat 的同时使用 $index 为所有兄弟姐妹提供 id,并在您执行 ng-repeat 的 div 上添加以下代码

    即。

    id="$index"
    

    使用

    ng-class={active: selected==$index}
    

    点击改变选中的值

    ng-click="selected=$index"
    

    您可以使用 $parent.$index 从您的内部访问父循环的索引 ng-重复循环

    【讨论】:

    • 我没有看到这个工作。 $index 不是 id,而是计数器。它为您提供当前循环的迭代。如果我有 2 个项目的循环,每个项目包含 2 个以上的项目,则索引将打印:0 0 1 1 0 1.
    • 因此,如果您可以访问父循环索引并将其与内部循环的索引相结合,您就可以唯一地确定元素
    【解决方案3】:

    以下是不是一个好的答案,但它是实用的。我想提供它,以便人们看到我能找到的唯一功能性解决方案有多糟糕:)

    如果您将控制器添加到递归树的每个叶子,并将悬停或单击处理程序附加到该控制器,您将可以访问处理程序中该级别的范围。因为scope提供了$parent的方法,可以爬上去拿兄弟。

    这听起来不是很不干净,但等你看看你必须爬出多少但丁式的关卡。

    Leaf.html:

    <a href
     ng-click="onClick($event, branch)"
     ng-controller="LeafController"
     >
    
    {{ branch.name }}
    <span ng-if="branch.children">&gt;</span>
    <ul ng-if="branch.children">
      <li ng-repeat="branch in branch.children">
        <ng-include src="'leaf.html'"></ng-include>
      </li>
    </ul>
    

    叶子控制器:

    angular.module('app').controller('LeafController', function($scope) 
      $scope.onClick = function(evt, leaf) {
        evt.stopPropagation();
        console.log('$scope', $scope); // Should be able to get to siblings now, right?
      };
    });
    

    现在可以在此位置访问兄弟对象(我希望我是在开玩笑):

    $scope.$parent.$parent.$parent.$parent.$parent.$parent.branch.children
    

    我不想依赖这个链条。一定有更好的方法吧?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-27
      • 1970-01-01
      • 1970-01-01
      • 2017-12-22
      • 2023-03-28
      • 2014-07-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多