2013-11-21 33 views
8

我解剖納克重複和提取附加的代碼塊,看到的是,這些包括處理該重複算法(我想了解它是如何工作)的邏輯。ng-repeat如何工作?

我有好幾個問題,但由於它們都是關於的內部NG-重複我選擇問他們都在這裏。我沒有看到任何理由將它們分成不同的SO問題。我已經標記了每個問題涉及哪些代碼行。

  1. 爲什麼他們需要確保trackById不是本地hasOwnProperty功能? (這是assertNotHasOwnProperty函數的一部分,是Angular的內部API的一部分)
  2. 就我的直覺而言,此代碼在已經在中繼器中的項目上執行,當它必須更新集合時 - 它只是將它們拾取並推送它們進入列表進行處理,對嗎?
  3. 此代碼塊顯然會在中繼器集合中查找重複項。但是,它究竟做了什麼,超越了我。請解釋。
  4. 爲什麼Angular必須存儲塊對象nextBlockMap in nextBlockOrder
  5. 什麼是block.endNodeblock.startNode
  6. 我假設的答案,上述問題將如何澄清這個算法工作,但請解釋爲什麼它檢查是否有nextNode(被)'$$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; 

回答

10

一些修修補補的指令後,我開始熟悉ng-repeater S碼,並設法回答一些我的問題。我在大膽的東西強調我還沒能弄清楚我自己,並希望如果任何人都可以在大膽部分提供一些線索:

  1. ID是hasOwnProperty測試,因爲他們使用該方法檢查迭代對象中是否存在該標識(lastBlockMap,nextBlockMap)(此過程在下面說明)。 但是,我無法找到這種情況實際發生的情況。
  2. 我在我的假設是正確的。 nextBlockMap包含在當前模型更改中將被跨越的所有項目。 lastBlockMap包含以前型號更新的所有內容。它用於查找集合中的重複項。
  3. 好吧,這個其實很簡單。在這種for循環,ng-repeat填補了nextBlockMaplastBlockMap項目。查看if的順序,很容易看出,如果在lastBlockMap中找不到該項目,但它已經存在於nextBlockMap(意思是它已經從lastBlockMap複製過來,因此它的trackById在該集合中出現兩次) - 它是重複的。什麼forEach確實是簡單的通過全部初始化項nextBlockMapblock S作一startNode屬性)運行,並推動其IDlastBlockMap但我不明白爲什麼這是必要的。
  4. 我能找到從nextBlockMap(所有block對象在trackById哈希)分離nextBlockOrder(陣列中的所有trackById S)的唯一原因,就是這條線,它使用數組使其成爲一個容易和簡單的操作: if (nextBlockOrder[index - 1]) previousNode = nextBlockOrder[index - 1].endNode;。它在問題5和6的答案中得到解釋:
  5. block.startNodeblock.endNode是屬於被重複收集的項目的塊中的第一個和最後一個DOM節點。因此,此處的此行將previousNode設置爲引用中繼器中前一項的最後一個DOM節點。
  6. previousNode然後被用作第一個節點,在一個循環中檢查當物品移動或從中繼器集合中移除時DOM如何改變 - 同樣,只有當我們不使用數組中的第一個塊時。
  7. 這很簡單 - 它初始化塊 - 指定$scopestartNodeendNode供以後參考,並將所有內容保存在nextBlockMap中。在克隆元素之後創建的評論,是爲了保證我們始終有一個endNode