为什么即使 *ngIf 设置为 true,@ViewChild 仍然未定义
我遇到了以下问题,该问题已由
@ViewChild
中的
{static: false>
属性修复。
此 stackoverflow 问答帮助解决了此问题
我应该如何在 Angular 8 中使用 @ViewChild 的新静态选项?
。
我想更好地理解这种情况以及
static
如何改变结果,以及变化检测如何影响这种情况。我在 Angular 文档中阅读了一些有关变化检测的内容,发现其中极其缺乏。
我想出了一个 stackblitz 来说明一些我不明白的事情。 Stackblitz angular 示例
当单击
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 中的完整代码)
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
@ViewChild("contentPlaceholder", { static: true })
trueViewChild: ElementRef;
@ViewChild("contentPlaceholder", { static: false })
falseViewChild: ElementRef;
display = false;
constructor() {}
show() {
console.log(this.trueViewChild, this.falseViewChild);
this.display = true;
console.log(this.trueViewChild, this.falseViewChild);
}
}
我的问题是:
-
为什么
this.falseViewChild
的第二行值显示为未定义。在设置this.display = false
后,变更检测是否应该运行,因此它不应该未定义? -
为什么
this.trueViewChild
保持未定义状态。我希望它在*ngIf
变为真后找到该元素?
Angular 变更检测在 zone.js 库的帮助下工作。 更新 ViewChild/Content 查询发生在变更检测周期中 。
zone.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 后,变更检测是否应该运行,因此它不应该是未定义的?
更改
display
属性时没有任何反应
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
}
这就是您在第一次点击时获得以下输出的原因:
> undefined undefined
> undefined undefined <---- nothing has updated
......
update happens here
它将稍后更新,但除非您再次点击,否则您不会看到此信息,因为您稍后不会记录这些值。
-
为什么 this.trueViewChild 保持未定义状态。我希望它在 *ngIf 变为 true 后找到该元素?
因为 Angular 文档 中有这样的规则:
With static queries (static: true), the query resolves once the view has been created, but before change detection runs. The result, though, will never be updated to reflect changes to your view, such as changes to ngIf and ngFor blocks.
这意味着如果它最初为
false
(例如,它在 *ngIf 或
ng-template
内),那么它将始终为
false