ngAfterViewInit与ngAfterContentChecked

时间:2019-04-02 13:24:48

标签: angular

此问题与在StackOverflow上问过很多次的问题有关。

基本上,当您执行类似操作

var points = []
for t in 0..<nbPoints {
    let current = from + directionVector * Float(t)
    points.append(current)
}
let duration = 5.0
let nbPoints = 40
let unitDuration = duration / Double(nbPoints)
self.gvrAudioEngine.playSound(self.sourceId, loopingEnabled: false)
for i in 0..<points.count {
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(i) * unitDuration, execute: {
        self.gvrAudioEngine.setSoundObjectPosition(
        self.sourceId, x: points[i].x, y: points[i].y, z: points[i].z)
    })
}

您会收到一条错误消息,提示“检查后表达式已更改” 。发生此错误的原因已在这篇文章中进行了解释: Expression ___ has changed after it was checked

我的问题是,为什么以下方法有效?

@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 :)'
  }
}

为什么这不返回错误,而实际上返回正确的结果?为什么ngAfterViewChecked起作用,而ngAfterViewInit不起作用?

像我5岁一样解释自己。

1 个答案:

答案 0 :(得分:1)

ngAfterViewInitngAfterContentChecked回调在Angular中为Lifecycle Hooks。也就是说,在您的Angular组件和指令的生命周期中的某些特定时间调用它们。

您正在经历的行为源于Angular的变更检测运行的时间点与这些生命周期挂钩中的每个被调用的时间点有关。

更具体地说,更改检测的第一个迭代在第一个ngAfterContentChecked钩之后,但在对ngAfterViewInit的调用之前。 / p>

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

通过在message挂钩内更改ngAfterContentChecked的值,将在更改检测的第一次迭代运行之前并对其进行设置。这意味着在随后的更改检测运行中,它将具有与第一次更改相同的值。这很好,而且正是变更检测器想要的。

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