Angular 为什么即使*ngIf设置为true,@ViewChild仍然未定义

Angular 为什么即使*ngIf设置为true,@ViewChild仍然未定义,angular,angular-ng-if,viewchild,Angular,Angular Ng If,Viewchild,我遇到了以下问题,该问题由@ViewChild中的{static:false}属性修复。 这个问题有助于解决这个问题 我想更好地理解这个场景,以及静态如何改变结果,以及变化检测如何影响这个场景。我在angular文档中阅读了一些关于变化检测的内容,发现这一点非常缺乏 我想出了一个stackblitz来说明一些我不理解的事情 单击两次toggle按钮时,我会在命令行上看到以下内容: > undefined undefined > undefined undefined > und

我遇到了以下问题,该问题由
@ViewChild
中的
{static:false}
属性修复。 这个问题有助于解决这个问题

我想更好地理解这个场景,以及
静态
如何改变结果,以及变化检测如何影响这个场景。我在angular文档中阅读了一些关于变化检测的内容,发现这一点非常缺乏

我想出了一个stackblitz来说明一些我不理解的事情

单击两次
toggle
按钮时,我会在命令行上看到以下内容:

> undefined undefined
> undefined undefined
> undefined ElementRef {nativeElement: div}
> undefined ElementRef {nativeElement: div}

然而,我预计:

> undefined undefined
> undefined ElementRef {nativeElement: div}
> ElementRef {nativeElement: div} ElementRef {nativeElement: div}
> ElementRef {nativeElement: div} ElementRef {nativeElement: div}

下面是代码的逻辑--(请参阅stackblitz中的完整代码)

@组件({
选择器:“我的应用程序”,
templateUrl:“./app.component.html”,
样式URL:[“/app.component.css”]
})
导出类AppComponent{
@ViewChild(“contentPlaceholder”,{static:true})
trueViewChild:ElementRef;
@ViewChild(“contentPlaceholder”,{static:false})
falseViewChild:ElementRef;
显示=假;
构造函数(){}
show(){
console.log(this.trueViewChild,this.falseViewChild);
this.display=true;
console.log(this.trueViewChild,this.falseViewChild);
} 
}

我的问题是:

  • 为什么
    this.falseViewChild
    的第二行值显示为未定义。设置
    this.display=false
    后不应该运行更改检测,因此不应该未定义它
  • 为什么
    this.trueViewChild
    保持未定义状态。我希望它在
    *ngIf
    变为true后找到元素

  • 角度变化检测在zone.js库的帮助下工作更新ViewChild/内容查询发生在更改检测周期中

    js库修补异步API(addEventListener、setTimeout()、Promises…),并准确地知道执行了哪个任务以及任务何时完成

    例如,当此任务已完成时,它可以侦听单击事件并发出通知(没有挂起的任务,这意味着区域变得稳定)

    Angular订阅这些通知,以便从根组件开始对所有三个组件执行更改检测

    // your code 
    (click)="someHandler()" 
    
    someHandler() {              
     ....
    }
    
    // angular core
    checkStable() {
      if (there is no any task being executed and there is no any async pending request) {
        PERFORM CHANGE DETECTION
      } 
    }
    
    代码中关于的顺序如下所示:

     click
      ||
      \/
    someHandler()
      ||
      \/
    checkStable()
      ||
      \/
    PERFORM CHANGE DETECTION
    
    那么,让我们回答您的问题:

  • 为什么this.falseViewChild的第二行值显示为未定义。设置this.display=false后不应该运行更改检测,因此它不应该是未定义的
  • 更改
    显示
    属性时没有反应

    show() {
     console.log(this.trueViewChild, this.falseViewChild);
     this.display = true;  <--- Angular doesn't do here anything, it only listens to zone state changes
     console.log(this.trueViewChild, this.falseViewChild); // nothing should be updated here 
                                                           // because there wasn't any cd cycle yet
    } 
    
    show(){
    console.log(this.trueViewChild,this.falseViewChild);
    this.display=true;未定义未定义
    
    >未定义未定义感谢您的深入回答。问题2现在有意义了。您的分叉堆栈闪电在第一次单击后没有显示任何内容,在第二次单击后仅显示一些内容
    。我只是想看看这是否是您的预期效果?是的,您是对的,我查看了不同的行为。第二次单击后,它也应该更新视图。第一个问题仍然有点不清楚。
    console.log(…)
    this.display=true;
    之后未定义,因为Angular尚未从zone.js收到订阅的值,还是因为zone.js没有查看这些更改?此代码在Angular zone内执行,zone知道只有在该处理程序执行Angular checks stat之后才会执行某些操作只有当没有挂起的任务时,它才会发出onMicrotaskEmpty事件。为了运行更改检测循环,已经订阅了此事件这是如何检查区域状态的
    > undefined undefined
    > undefined undefined   <---- nothing has updated
    
     ......
     update happens here