ngAfterViewInit 与 ngAfterContentChecked

Aso*_*ool 2 angular

这个问题与 StackOverflow 上被问过很多次的问题相关。

基本上,当你做类似的事情时

@Component({
  selector: 'my-app',
  template: `<div>I'm {{message}} </div>`,
})
export class App {
  message:string = 'loading :(';

  ngAfterViewInit() {
    this.updateMessage();
  }

  updateMessage(){
    this.message = 'all done loading :)'
  }
}
Run Code Online (Sandbox Code Playgroud)

您收到一条错误消息“表达式在检查后已更改”。收到此错误的原因已在这篇文章中进行了解释: Expression ___ haschange after it was Check

我的问题是,为什么以下内容有效?

@Component({
  selector: 'my-app',
  template: `<div>I'm {{message}} </div>`,
})
export class App {
  message:string = 'loading :(';

  ngAfterContentChecked() {
    this.updateMessage();
  }

  updateMessage(){
    this.message = 'all done loading :)'
  }
}
Run Code Online (Sandbox Code Playgroud)

为什么这不返回错误,并且实际上返回正确的结果?为什么 ngAfterViewChecked 有效,而 ngAfterViewInit 无效?

解释得像我5岁一样。

Dar*_*ane 5

和回调是AngularngAfterViewInit中的生命周期挂钩。也就是说,它们在 Angular 组件和指令的生命周期中的某些特定时间被调用。ngAfterContentChecked

您遇到的行为源于 Angular 的更改检测运行的时间点与调用每个生命周期挂钩的时间点相关的时间点。

更具体地说,更改检测的第一次迭代在第一个挂钩之后ngAfterContentChecked但在调用之前ngAfterViewInit运行。

我在这里创建了一个 Stackblitz 演示(在控制台中查看)来说明对这些生命周期挂钩和更改检测运行的调用流程,但我还将在这里总结我的发现:

message通过更改钩子内部的值,其值将在变化检测的第一次迭代运行并发现它之前ngAfterContentChecked设置。这意味着在后续的更改检测运行中,它将具有与第一次运行时相同的值。这很好,也正是变化检测器想要的。

相反,通过设置message钩子内部的值,其值将在变化检测运行的第一次迭代ngAfterViewInit设置。换句话说,当第一次迭代运行并评估 时,它将看到它的值为,之后直接调用它会更改其值。后续的更改检测运行将评估为这当然与之前的迭代值不同,因此会抛出 an 。messageloading :( ngAfterViewInitmessageall done loading :)loading :(ExpressionChangedAfterItHasBeenCheckedError