当前位置: 首页 > 面试题库 >

ng-repeat如何工作?

哈襦宗
2023-03-14
问题内容

我剖析了ng-repeat并提取了附加的代码块,看到它们包含处理 重复 算法的逻辑(我想了解它的工作原理)。

我有很多问题,但是由于它们都是关于ng-
repeat的内部结构,因此我选择在这里全部询问。我看不出有任何理由将它们分为不同的SO问题。我已标记内联每个问题所指向的代码行。

  1. 为什么他们需要确保这trackById不是本机hasOwnProperty函数?(这就是该assertNotHasOwnProperty功能的作用,是Angular内部API的一部分)
  2. 就我的直觉而言,此代码在必须更新转发器的项目上对转发器中已有的项目执行-它只是将它们拾取并将其推入列表进行处理,对吗?
  3. 代码块显然在转发器集合中查找重复项。但是,如何做到这一点超出了我。请解释。
  4. 为什么角有存储块对象都nextBlockMap nextBlockOrder
  5. 什么是block.endNodeblock.startNode
  6. 我认为上述问题的答案将阐明该算法的工作原理,但是请解释为什么它必须检查nextNodehas(been)'$$NG_REMOVED'吗?
  7. 这里会发生什么?再一次,我认为问题6已经可以回答这个问题。但仍然指出这一点。

就像我说的那样,我通过ng-
repeat进行了查找,找到了我认为与重复机制相关的代码。另外,我确实了解该指令的其余部分。因此,事不宜迟,这是代码(来自v1.2.0):

      length = nextBlockOrder.length = collectionKeys.length;
      for (index = 0; index < length; index++) {
       key = (collection === collectionKeys) ? index : collectionKeys[index];
       value = collection[key];
       trackById = trackByIdFn(key, value, index);

       // question #1
       assertNotHasOwnProperty(trackById, '`track by` id');

       // question #2
       if (lastBlockMap.hasOwnProperty(trackById)) {
         block = lastBlockMap[trackById];
         delete lastBlockMap[trackById];
         nextBlockMap[trackById] = block;
         nextBlockOrder[index] = block;

       // question #3
       } else if (nextBlockMap.hasOwnProperty(trackById)) {
         // restore lastBlockMap
         forEach(nextBlockOrder, function(block) {
           if (block && block.startNode) lastBlockMap[block.id] = block;
         });
         // This is a duplicate and we need to throw an error
         throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
                                                                                                                                                expression,       trackById);

       // question #4
       } else {
         // new never before seen block
         nextBlockOrder[index] = { id: trackById };
         nextBlockMap[trackById] = false;
       }
     }


      for (index = 0, length = collectionKeys.length; index < length; index++) {
        key = (collection === collectionKeys) ? index : collectionKeys[index];
        value = collection[key];
        block = nextBlockOrder[index];


        // question #5
        if (nextBlockOrder[index - 1]) previousNode = nextBlockOrder[index - 1].endNode;

        if (block.startNode) {
          // if we have already seen this object, then we need to reuse the
          // associated scope/element
          childScope = block.scope;

          // question #6
          nextNode = previousNode;
          do {
            nextNode = nextNode.nextSibling;
          } while(nextNode && nextNode[NG_REMOVED]);
          if (block.startNode != nextNode) {
            // existing item which got moved
            $animate.move(getBlockElements(block), null, jqLite(previousNode));
          }
          previousNode = block.endNode;

        } else {
          // new item which we don't know about
          childScope = $scope.$new();
        }

        // question #7
        if (!block.startNode) {
          linker(childScope, function(clone) {
            clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
            $animate.enter(clone, null, jqLite(previousNode));
            previousNode = clone;
            block.scope = childScope;
            block.startNode = previousNode && previousNode.endNode ? previousNode.endNode : clone[0];
            block.endNode = clone[clone.length - 1];
            nextBlockMap[block.id] = block;
          });
        }
      }
      lastBlockMap = nextBlockMap;

问题答案:

在修改了该指令之后,我开始熟悉ng-repeaters代码,并设法回答了我的一些问题。我以 粗体
突出显示了我自己还无法解决的问题,如果有人可以对 粗体 部分有所了解,我将不胜感激:

  1. 该ID用于测试hasOwnProperty,因为它们使用的方法来检查ID是否存在于迭代的对象(lastBlockMapnextBlockMap)(该过程在下面解释)。 但是,我无法确定在什么情况下会发生这种情况。
  2. 我的假设是正确的。nextBlockMap包含在当前模型更改中将被排除的所有项目。lastBlockMap包含上一次模型更新中的所有内容。它用于在集合中查找重复项。
  3. 好的,这实际上很简单。在此for循环中,ng-repeat填充的nextBlockMap项目lastBlockMap。查看ifs 的顺序,很容易看到,如果在中找不到该项目lastBlockMap,但它已经存在于中nextBlockMap(意味着它已经从中复制了lastBlockMap,因此trackById在集合中出现了两次)-它是重复项。什么forEach确实是简单地通过全部初始化项目运行nextBlockMapblockS作一个startNode属性),推动 其IDlastBlockMap但是,我不明白为什么这样做是必要的。
  4. 我可以找到将nextBlockOrdertrackById数组中的所有s)与nextBlockMap(哈希中的所有block对象)分开的唯一原因trackById是这一行,它与数组一起使用使操作变得简单if (nextBlockOrder[index - 1]) previousNode = nextBlockOrder[index - 1].endNode;。问题5和6的答案对此进行了解释:
  5. block.startNode并且block.endNode是重复的,属于该收集项中项目的块中的第一个和最后一个DOM节点。因此,此行此处设置previousNode为引用转发器中上一项的最后一个DOM节点。
  6. previousNode 然后,在循环中检查第一个节点时,该循环检查当项目在转发器集合中移动或从转发器集合中移除时DOM的变化-同样,仅在我们不使用数组中的第一个块的情况下。
  7. 这很容易-初始化块$scopestartNode并分配和和endNode供以后参考,并将所有内容保存在中nextBlockMap。在克隆元素之后立即创建的注释可以确保我们始终有一个endNode


 类似资料:
  • 问题内容: 嗨,我有一个简单的ng-repeat-start和end用例,并且工作正常,当我想添加一个内部ng-repeat时出现了问题。这是我的代码 内部ng-repeat到td元素中不起作用,在检查html源代码时看到ngRepeat注​​释,但未创建td元素。 我的丑陋的解决方法(假设我知道该向量的大小)是: 问题答案: 从那时起,我不确定是否使用角度1.1.6,并且在1.1.5或1.0.7

  • 问题内容: 我试图了解over 的意义。角度文档提供了以下示例 但是,使用, 有人可以解释。的意义吗?谢谢。 问题答案: 这两个指令的含义相似:它们重复HTML标记。所不同的只是,在您的帮助下,您可以重复几个标签,从标签开始于,再到完成于。 例如,您有下一个代码: 因此,现在我们可以为这些代码添加2个指令。 与: 与和: 因此,现在您可以看到,在第一种情况下,仅使用指令重复,但是在第二种情况下,您

  • 问题内容: 我正在尝试使用数组来过滤并在列表中显示信息。为此,我使用了inbuild 方法。 但是我遇到了错误。 这是我的尝试(我通过过滤) 现场演示 问题答案: AngularJS 默认不包含过滤器。您可以使用angular- filter中的 那个。只包含JavaScript 并在您的应用中添加依赖项: 您的代码应立即生效!我编辑了您的Plunker,使其正常工作。

  • 问题内容: 我正在开发一个页面,我需要在其中显示一些框(使用),其中包含频道信息以及显示位置(城市)。 我面临的问题是当我重复第二遍时: 这应该获得第一个ng-repeat的$ index值,并使用显示频道的位置创建一个新数组。它确实做到了。但是,当我使用此数组应用第二个ng- repeat时,它无法正常工作。 说我的html看起来像这样(PS:我需要使用索引值而不是因为我将这些框放到列中) JS

  • 问题内容: 我有一些虚拟XML文件: 使用此库http://code.google.com/p/x2js/将其转换为json,并转换为变量 Day可以具有任意数量的Job,Job可以嵌套并且包含任意数量的其他Job。 现在使用此代码 我可以列出有效的日期。我希望使用以下代码 我可以列出当天的工作日和最高职位,但这是行不通的。(要列出嵌套的Jobs,将是下一个任务,而不是现在询问该任务)。 那么,如

  • 问题内容: 我想使用父列表(foos)的索引作为子列表(foos.bars)中函数调用的参数。 我发现了有人建议使用$ parent。$ index的帖子,但不是的属性。 如何访问父级的索引? 问题答案: 我的示例代码是正确的,问题出在我的实际代码中。不过,我知道很难找到这样的例子,所以我在回答别人的情况。