8
我解剖納克重複和提取附加的代碼塊,看到的是,這些包括處理該重複算法(我想了解它是如何工作)的邏輯。ng-repeat如何工作?
我有好幾個問題,但由於它們都是關於的內部NG-重複我選擇問他們都在這裏。我沒有看到任何理由將它們分成不同的SO問題。我已經標記了每個問題涉及哪些代碼行。
- 爲什麼他們需要確保
trackById
不是本地hasOwnProperty
功能? (這是assertNotHasOwnProperty
函數的一部分,是Angular的內部API的一部分) - 就我的直覺而言,此代碼在已經在中繼器中的項目上執行,當它必須更新集合時 - 它只是將它們拾取並推送它們進入列表進行處理,對嗎?
- 此代碼塊顯然會在中繼器集合中查找重複項。但是,它究竟做了什麼,超越了我。請解釋。
- 爲什麼Angular必須存儲塊對象
nextBlockMap
和 innextBlockOrder
? - 什麼是
block.endNode
和block.startNode
? - 我假設的答案,上述問題將如何澄清這個算法工作,但請解釋爲什麼它檢查是否有
nextNode
(被)'$$NG_REMOVED'
? - 這裏會發生什麼?我再次假設問題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;