gpt4 book ai didi

angular - 执行插值,即使 ChangeDetectorRef 已分离

转载 作者:太空狗 更新时间:2023-10-29 18:24:28 27 4
gpt4 key购买 nike

我有以下情况:

  • 根组件有一个 <h1>使用点击处理程序(根组件使用 ChangeDetectionStrategy.Default)
  • 在可点击的 <h1> 下方-Element 是另一个组件,它呈现一些行。指定了一个模板,它定义了如何呈现一行(并且函数调用用于获取要呈现的值。我知道,对于这种情况,函数没有意义,但它显示了问题)
  • 呈现行的组件与更改检测分离
  • 如果我点击 <H1> -Element,尽管它与更改检测分离,但会为组件中的每一行再次调用该函数。这是怎么回事?

应用程序组件.html:

<h1 (click)="onClick()" style="cursor:pointer">Klick me</h1>

<app-rows [rows]="rows">
<ng-template let-row="rowData">
{{getName(row)}}
</ng-template>
</app-rows>

应用程序组件.ts:

@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {

rows: any[];

constructor(private changeDetectorRef: ChangeDetectorRef, private renderer: Renderer2) {
this.rows = this.createRows(100);
}

getName(row:any): string {
console.log("getName called")
return row.name;
}

onClick() {
console.log("clicked");
}

private createRows(count:number): any[] {
let rows: any[] = [];

for (let i=0; i < count; i++) {
rows.push({
name: "TEST " + (i+1)
})
}
return rows;
}
}

行.组件.html

<div *ngFor="let row of rows">
<ng-container *ngTemplateOutlet="template; context: {'rowData': row}">
</ng-container>
</div>

行.component.ts:

@Component({
selector: 'app-rows',
templateUrl: './rows.component.html'
})
export class RowsComponent {

@Input()
rows: any[];

@ContentChild(TemplateRef)
template: TemplateRef<any>;

constructor(private changeDetector: ChangeDetectorRef) {
}

ngAfterViewInit() {
this.changeDetector.detach();
}
}

可以在 stackblitz 找到运行示例

我已经将 CLI 项目上传到 DropBox


更新:我试图在两者之间添加一个额外的组件来稍微改变组件层次结构。但它不会改变行为。此版本可在 enter link description here 找到

最佳答案

实际上有点复杂,您所看到的行为的罪魁祸首是内容投影。根据 Web 组件域,这似乎是普通组件的正确行为。托管组件内的每个投影节点都属于托管组件。因此,如果您的根 my-app 组件具有以下模板:

<a-comp>
<b-comp>
<d-comp></d-comp>
</b-comp>
</a-comp>

b-compd-comp 都属于 my-app 组件,都被认为是投影的。在这里你可以直观地看到它(使用原生影子根):

enter image description here

您的情况有点不同,因为您要投影模板。在 Angular 中,当一个模板被投影到另一个组件中时,所有使用它创建的 View 也被认为是被投影的。并且在检查模板所属的组件时检查它们。

AppComponent 模板中,您有以下内容:

<app-rows [rows]="rows">
<ng-template let-row="rowData">
{{getName(row)}}
</ng-template>
</app-rows>

此处 ng-templateAppComponent View 的子项,并投影到 AppRowsComponent 中。此模板也绑定(bind)到 AppComponent,但上下文可以更改 - 您是从 RowsComponent 设置它。

Here is a much simpler example在哪里可以看到这种行为。当绑定(bind)的父组件属性更新时,分离组件内的投影 View 也会更新。

当 Angular 在 AppComponent 上运行变更检测时,它会检查是否应该检查其子组件。由于 AppRowsComponent 是分离的,因此不会对其运行更改检测。但是,应该检查使用绑定(bind)到 AppComponent 的模板创建的投影 View ,因此在检查投影 View 的变更检测实现中有一个逻辑:

// `view` here is a container for `AppRowsComponent`
case ViewAction.CheckAndUpdateProjectedViews:
if ((viewState & 128 /* Destroyed */) === 0) {
if (viewState & 32 /* CheckProjectedView */) {
checkAndUpdateView(view); <----- skipped for AppRowsComponent sicne it's not projected
}
else if (viewState & 64 /* CheckProjectedViews */) {
execProjectedViewsAction(view, action); <---- this is executed
}
}
break;

要了解有关变化检测的更多信息,请从:

开始

关于angular - 执行插值,即使 ChangeDetectorRef 已分离,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48096659/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com