【问题标题】:Angular ng-content different behaviour while using selectAngular ng-content 使用选择时的不同行为
【发布时间】:2021-03-28 14:59:38
【问题描述】:

据我们所知,仅在最后匹配的 ng-content 中使用 ng-content 项目内容,但我不明白的是,为什么在使用 select 和项目时它的行为相反。

第一个子组件

1
<ng-content select=".my-class"></ng-content> <br>
2
<ng-content select=".my-class"></ng-content>

第二个子组件

1
<ng-content></ng-content> <br>
2
<ng-content></ng-content>

父组件

<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>

结果

1 CHILD
2
--------
1
2 CHILD

Stackblitz

【问题讨论】:

  • 是的,这就是问题所在。那为什么它在不使用 select 的情况下将内容投影到最后一个 ng-content 中。我认为预期会得到相同的结果,因为在这两个示例中,首先匹配 ng-content
  • 这是不一致且很大程度上是任意行为 AFAICT。鉴于在这两种情况下,代码在语义上都是错误的,并且很可能代表一个错误,因此差别不大

标签: angular


【解决方案1】:

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 编译器的源代码。

默认&lt;ng-content&gt;&lt;/ng-content&gt;

<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值。

【讨论】:

    猜你喜欢
    • 2020-03-22
    • 2019-07-11
    • 2021-05-07
    • 2017-05-07
    • 1970-01-01
    • 2018-11-04
    • 2019-01-17
    • 2018-01-02
    • 1970-01-01
    相关资源
    最近更新 更多