元素操纵之 @View/ContentChild

Photo by Walter Cheung on Unsplash

有时候,我们希望直接操纵页面上的元素或组件。为此,Angular 为我们提供了 @ViewChild 和 @ContentChild 来获得页面元素的引用。

@ViewChild

@ViewChild 是可以获取模板上指令、组件、基本元素甚至子元素服务的引用。我们这样使用 ViewChild 来引用视图中的 DataComponent 组件。

@ContentChild

相比 @ViewChild,@ContentChild 最大的特点在于它只能用来获取投影中指令、组件、基本元素的引用。假如我们有这样一个组件 app-child,我们将一个组件 DataComponent 作为投影传入 app-child 中。

然后在 app-child 中使用 @ContentChild 来获取 DataComponent 的引用。

参数 selector

@ViewChild 和 @ContentChild 的第一个参数是 selector,用来定位需要操作的对象元素。它支持模板引用的字串、组件和指令类型等多种定位方式。

选项 read

read 选项是可选的选项。通过它来将我们元素的引用转换为想要的类型。若我想把 DataComponent 元素的引用改成 ElementRef 的引用,可以这样操作。

若不指定 read,那么会根据元素的类型转换成对应的引用。比如组件、指令就会转化为对应的组件和指令类。<ng-template> 会转换成 TemplateRef。而普通元素会转化为 ElementRef。

选项 static

在当前版本 static 没有默认值(NG 9 之后会默认为 false),需要手动设定。static 的字面意思是静态。一般来说,不需要 Angular 在变更检测时解析得到的元素就是静态。也可以把静态元素看成是不与绑定两字搭边的元素,如下所示就是一个静态元素。因为此元素上没有作用任何的绑定数据。

反之,与绑定元素相关的,就是非静态元素,如下图所示。此元素上作用了与绑定相关的 ngIf 指令。Angular 必须要在变更检测阶段判断绑定变量的值后才能决定是否显示此元素。此元素就是非静态元素。

在没有 static 选项之前,我们只能在变更检测的 AfterViewInit 生命周期钩子中才能安全地获得 @ViewChild 修饰的变量的引用。但是这远远不够。当我们利用 @ViewChild @ContentChild 获取元素引用,并用之来创建嵌入式视图时会触发一个异常。我们可以来看看这个异常产生的原因。

一、元素引用需要在 ngAfterViewInit 中获取。

二、 ngAfterViewInit 时 View 已做过变化检测,故不能再对其做修改。

因此此时会抛出 ExpressionChangedAfterItHasBeenCheckedError 异常。下面就是一个异常例子

为此,Angular 在 @ViewChild 和 @ContentChild 中引入一个 static 选项。一旦将其设置为 true,就可以让 Angular 在视图构造阶段之后,变更检测之前查询目标元素。这最终意味着,我们可以在 ngOnInit 中安全地得到这些静态元素的引用,并使用 createEmbbedView 来创造一个嵌入式视图。这里是一个在线例子

一般来说,我们还是将 static 置位 false,除非你想在 ngOnInit 中就要得到静态元素的引用。需要注意的是这里的静态与否需要

参考文献

Angular @ViewChild: In-Depth Explanation (All Features Covered)

Angular ViewChild 官方文档

Angular ContentChild 官方文档

ViewChildren & ContentChildren

Static Query Migration Guide 官方文档对于 static 参数最好的注解

发表评论

电子邮件地址不会被公开。 必填项已用*标注