为什么异步函数导致ViewChild在ngOnInit()中为undefined?

15 浏览
0 Comments

为什么异步函数导致ViewChild在ngOnInit()中为undefined?

这是一个组件,其中有一个ViewChild引用了html中的#h1:\n

import { Component, ElementRef, ViewChild } from '@angular/core';
@Component({
  selector: 'app-root',
  template: `
  

欢迎来到{{title}}!

`, styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'app'; public showh1: boolean = false; @ViewChild('h1') h1: ElementRef; ngOnInit() { setTimeout(() => { //实际情况中的http.get this.showh1 = true; console.log('h1:' + this.h1); //h1:undefined setTimeout(() => { console.log('h2:' + this.h1); //h2:[object Object] }, 1); }, 1000); } }

\n为什么在`console.log(\'h1:\' + this.h1);`处`this.h1`是`undefined`?\n2020年11月更新\n如果您使用的是最新的Angularv9,它具有`@ViewChild`上的static选项,您就不会遇到这种情况。

0
0 Comments

在ngOnInit()中,当使用了async函数时,导致ViewChild未定义的问题。出现这个问题的原因是,由于ngIf中的条件在此时尚未被变更检测重新评估,因此元素尚未在视图中。需要理解的是,变更检测和DOM更新不会在每个代码指令之后都执行。即使可能,这也会导致性能问题。

循环基本上包括以下步骤:

  1. 检测事件(如超时、异步HTTP响应或某些DOM事件,如点击)
  2. 执行处理此事件的代码
  3. 检测组件状态的变化,以及模板中使用的表达式(如showh1
  4. 更新DOM
  5. 返回步骤1

解决这个问题的方法是使用ngAfterViewInit()而不是ngOnInit()来访问ViewChild。因为ngAfterViewInit()是在视图初始化之后调用的,所以可以确保ViewChild已经被定义。以下是解决方法的示例代码:

import { Component, ViewChild, AfterViewInit } from '@angular/core';
@Component({
  selector: 'app-example',
  template: `
    

Hello World

`, }) export class ExampleComponent implements AfterViewInit { @ViewChild('myElement') myElement: ElementRef; showh1: boolean = false; ngAfterViewInit() { // Access ViewChild here console.log(this.myElement); } }

通过将访问ViewChild的代码放在ngAfterViewInit()中,可以确保在元素已经在视图中定义之后再进行访问。这样就可以避免在ngOnInit()中访问ViewChild时出现未定义的问题。

0