Angular 编译器计算所谓的ngContentIndex。你可以把它想象成一个应该投射嵌入节点的地方。
所以,有AppComponent 模板
<app-first>
<ng-container class="my-class">CHILD</ng-container>
</app-first>
<br>--------<br>
<app-second>
<ng-container class="my-class">CHILD</ng-container>
</app-second>
Angular 给每个节点一个ngContentIndex(看看括号):
<app-first>(null)
<ng-container class="my-class">CHILD</ng-container>(1)
</app-first>
<br>--------<br>(null)
<app-second>(null)
<ng-container class="my-class">CHILD</ng-container>(0)
</app-second>
这意味着第一个CHILD应该转到第二个ng-content,第二个CHILD应该转到第一个。
为什么会这样?
答案在于 Angular 编译器的源代码。
默认<ng-content></ng-content>与
<ng-content select="*"></ng-content>
对于每个模板,Angular 都知道它的所有ngContentSelectors:
FirstComponent ['*', '*']
SecondComponent ['.my-class', '.my-class']
这里是the answer:
const ngContentSelectors = component.directive.template !.ngContentSelectors;
for (let i = 0; i < ngContentSelectors.length; i++) {
const selector = ngContentSelectors[i];
if (selector === '*') {
wildcardNgContentIndex = i;
} else {
matcher.addSelectables(CssSelector.parse(ngContentSelectors[i]), i);
}
}
您可以看到 Angular 对* 进行了特殊处理,并在循环中更新了wildcardNgContentIndex,使其成为1。对于['.my-class', '.my-class'] 数组,它将选择器添加到匹配项中。
最后,Angular 使用了this method:
findNgContentIndex(selector: CssSelector): number | null {
const ngContentIndices: number[] = [];
this._ngContentIndexMatcher.match(selector, (selector, ngContentIndex) => {
ngContentIndices.push(ngContentIndex);
});
ngContentIndices.sort();
if (this._wildcardNgContentIndex != null) {
ngContentIndices.push(this._wildcardNgContentIndex);
}
return ngContentIndices.length > 0 ? ngContentIndices[0] : null;
}
这将为FirstComponent中的可投影节点返回保存的1值。