关于angular8:我应该如何在Angular 8中为@ViewChild使用新的静态选项?

How should I use the new static option for @ViewChild in Angular 8?

我应该如何配置新的Angular 8视图子级?

1
2
@ViewChild('searchText', {read: ElementRef, static: false})
public searchTextInput: ElementRef;

1
2
@ViewChild('searchText', {read: ElementRef, static: true})
public searchTextInput: ElementRef;

哪个更好? 我什么时候应该使用static:true vs static:false


在大多数情况下,您将要使用{static: false}。这样设置,将确保找到依赖于绑定分辨率的查询匹配项(例如结构指令*ngIf, etc...)。

何时使用static: false的示例:

1
2
3
4
5
6
7
8
9
10
11
12
@Component({
  template: `
    Am I here?
    <button (click)="showMe = !showMe"></button>
  `
})
export class ExampleComponent {
  @ViewChild('viewMe', { static: false })
  viewMe?: ElementRef<HTMLElement>;

  showMe = false;
}

static: false将成为Angular 9中的默认回退行为。在此处和此处了解更多。

引入了{ static: true }选项以支持动态创建嵌入式视图。当动态创建视图并希望访问TemplateRef时,您将无法在ngAfterViewInit中执行此操作,因为这将导致ExpressionHasChangedAfterChecked错误。将static标志设置为true将在ngOnInit中创建视图。

不过:

In most other cases, the best practice is to use {static: false}.

请注意,尽管{ static: false }选项在Angular 9中将成为默认选项。这意味着不再需要设置静态标志,除非您要使用static: true选项。

您可以使用angular cli ng update命令来自动升级当前代码库。

有关迁移指南以及更多有关此的信息,可以在此处和此处查看

What is the difference between static and dynamic queries?

The static option for @ViewChild() and @ContentChild() queries determines when the query results become available.

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.

With dynamic queries (static: false), the query resolves after either ngAfterViewInit() or ngAfterContentInit() for @ViewChild() and @ContentChild() respectively. The result will be updated for changes to your view, such as changes to ngIf and ngFor blocks.


因此,根据经验,您可以执行以下操作:

  • 当您要访问ngOnInit中的ViewChild时,需要设置{ static: true }

  • { static: false }只能在ngAfterViewInit中访问。当模板中的元素上具有结构化指令(即*ngIf)时,这也是您要追求的目标。


从角度文档

static - whether or not to resolve query results before change detection runs (i.e. return static results only). If this option is not provided, the compiler will fall back to its default behavior, which is to use query results to determine the timing of query resolution. If any query results are inside a nested view (e.g. *ngIf), the query will be resolved after change detection runs. Otherwise, it will be resolved before change detection runs.

如果孩子不依赖任何条件,最好使用static:true。如果元素的可见性发生变化,则static:false可能会提供更好的结果。

PS:由于它是一项新功能,我们可能需要运行性能基准。

编辑

如@Massimiliano Sartoretto所述,github commit可能会为您提供更多见解。


来到这里是因为在升级到Angular 8后,ngOnInit中的ViewChild为null。

静态查询在ngOnInit之前填充,而动态查询(静态:false)在之后填充。换句话说,如果在设置static:false后ngOnInit中的viewchild现在为null,则应考虑更改为static:true或将代码移至ngAfterViewInit。

参见https://github.com/angular/angular/blob/master/packages/core/src/view/view.ts#L332-L336

其他答案是正确的,并解释了为什么会这样:查询依赖于结构指令,例如ngIf内的ViewChild引用应在解析此伪指令的条件之后(即更改检测之后)运行。但是,可以安全地使用static:true,从而在ngOnInit之前解析查询以获取未嵌套的引用。恕我直言,这种特殊情况值得一提,因为空异常可能是您遇到这种特殊性的第一种方式,对我而言。


查看子@angular 5+令牌两个参数("本地引用名称",静态:false | true)

1
@ViewChild('nameInput', { static: false }) nameInputRef: ElementRef;

知道真假之间的区别检查此

static - whether or not to resolve query results before change detection runs (i.e. return static results only). If this option is not provided, the compiler will fall back to its default behavior, which is to use query results to determine the timing of query resolution. If any query results are inside a nested view (e.g. *ngIf), the query will be resolved after change detection runs. Otherwise, it will be resolved before change detection runs.


在ng8中,您可以手动设置何时访问父组件中的子组件。
将static设置为true时,这意味着父组件仅在onInit挂钩中获得该组件的定义:
例如:

1
2
3
4
5
6
7
8
 // You got a childComponent which has a ngIf/for tag
ngOnInit(){
  console.log(this.childComponent);
}

ngAfterViewInit(){
  console.log(this.childComponent);
}

如果static为false,则仅在ngAfterViewInit()中得到定义,在ngOnInit()中得到未定义。