简介
本文将向您介绍 Angular 的 ViewChild
装饰器。
在某些情况下,您可能希望从父组件类中访问指令、子组件或 DOM 元素。ViewChild
装饰器返回与给定指令、组件或模板引用选择器匹配的第一个元素。
先决条件
如果您想要跟随本教程进行操作:
- 考虑安装
@angular/cli
。 - 使用
@angular/cli
创建一个新项目,以测试ViewChild
在其中的功能。
本教程已经验证过可以在 @angular/core
v13.0.2 和 @angular/cli
v13.0.3 下使用。
使用 ViewChild
与指令
ViewChild
使得访问指令成为可能。
假设您有一个 SharkDirective
。该指令将查找具有属性 appShark
的元素,并在元素的文本前面添加单词 "Shark"
。
理想情况下,您将使用 @angular/cli
来 generate
您的指令:
ng generate directive shark --skip-tests
此命令将创建一个 shark.directive.ts
文件,并将该指令添加到 app.module.ts
:
import { SharkDirective } from './shark.directive';
...
@NgModule({
declarations: [
App***ponent,
SharkDirective
],
...
})
然后,使用 ElementRef
和 Renderer2
来重写文本。将 shark.directive.ts
的内容替换为以下内容:
import {
Directive,
ElementRef,
Renderer2
} from '@angular/core';
@Directive(
{ selector: '[appShark]' }
)
export class SharkDirective {
creature = 'Dolphin';
constructor(elem: ElementRef, renderer: Renderer2) {
let shark = renderer.createText('Shark ');
renderer.appendChild(elem.nativeElement, shark);
}
}
接下来,在组件模板中的一个包含文本的 span
中添加一个 appShark
属性。将 app.***ponent.html
的内容替换为以下内容:
<span appShark>Fin!</span>
在浏览器中查看应用程序时,将在元素的内容之前呈现单词 "Shark"
:
Shark Fin!
现在,您还可以访问 SharkDirective
的 creature
实例变量,并使用其值设置一个 extraCreature
实例变量。将 app.***ponent.ts
的内容替换为以下内容:
import {
***ponent,
ViewChild,
AfterViewInit
} from '@angular/core';
import { SharkDirective } from './shark.directive';
@***ponent({
selector: 'app-root',
templateUrl: './app.***ponent.html',
styleUrls: ['./app.***ponent.css']
})
export class App***ponent implements AfterViewInit {
extraCreature!: string;
@ViewChild(SharkDirective)
set appShark(directive: SharkDirective) {
this.extraCreature = directive.creature;
};
ngAfterViewInit() {
console.log(this.extraCreature); // Dolphin
}
}
此代码使用了一个 setter 来设置 extraCreature
变量。请注意,它等待 AfterViewInit
生命周期钩子来访问变量,因为这是子组件和指令可用的时候。
在浏览器中查看应用程序时,您仍将看到 "Shark Fin!"
消息。但是,在控制台日志中,它将显示:
Dolphin
父组件能够访问指令的值。
使用 ViewChild
与 DOM 元素
ViewChild
使得访问具有模板引用变量的本机 DOM 元素成为可能。
假设您在模板中有一个带有 #someInput
引用变量的 <input>
。将 app.***ponent.html
的内容替换为以下内容:
<input #someInput placeholder="Your favorite sea creature">
现在,您可以使用 ViewChild
访问 <input>
并设置 value
。将 app.***ponent.ts
的内容替换为以下内容:
import {
***ponent,
ViewChild,
AfterViewInit,
ElementRef
} from '@angular/core';
@***ponent({
selector: 'app-root',
templateUrl: './app.***ponent.html',
styleUrls: ['./app.***ponent.css']
})
export class App***ponent implements AfterViewInit {
@ViewChild('someInput') someInput!: ElementRef;
ngAfterViewInit() {
this.someInput.nativeElement.value = 'Whale!';
}
}
当 ngAfterViewInit
触发时,<input>
的值将被设置为:
Whale!
父组件能够设置子 DOM 元素的值。
使用 ViewChild
与子组件
ViewChild
使得访问子组件并调用子组件可用的方法或访问实例变量成为可能。
假设您有一个 Pup***ponent
。
理想情况下,您将使用 @angular/cli
来 generate
您的组件:
ng generate ***ponent pup --flat --skip-tests
此命令将创建 pup.***ponent.ts
、pup.***ponent.css
和 pup.***ponent.html
文件。并将该组件添加到 app.module.ts
:
import { Pup***ponent } from './pup.***ponent';
...
@NgModule({
declarations: [
App***ponent,
Pup***ponent
],
...
})
然后,在 Pup***ponent
中添加一个返回消息的 whoAmI
方法:
import { ***ponent, OnInit } from '@angular/core';
@***ponent({
selector: 'app-pup',
templateUrl: './pup.***ponent.html',
styleUrs: ['./pup/***ponent.css']
})
export class Pup***ponent implements OnInit {
constructor() { }
whoAmI() {
return 'I am a pup ***ponent!';
}
ngOnInit(): void {
}
}
接下来,在应用程序模板中引用子组件。将 app.***ponent.html
的内容替换为以下内容:
<app-pup>pup works!</app-pup>
现在,您可以使用 ViewChild
在父组件类中调用 whoAmI
方法。将 app.***ponent.ts
的内容替换为以下内容:
import {
***ponent,
ViewChild,
AfterViewInit
} from '@angular/core';
import { Pup***ponent } from './pup.***ponent';
@***ponent({
selector: 'app-root',
templateUrl: './app.***ponent.html',
styleUrls: ['./app.***ponent.css'],
})
export class App***ponent implements AfterViewInit {
@ViewChild(Pup***ponent) pup!: Pup***ponent;
ngAfterViewInit() {
console.log(this.pup.whoAmI()); // I am a pup ***ponent!
}
}
在浏览器中查看应用程序时,控制台日志将显示:
I am a pup ***ponent!
父组件能够调用子组件的 whoAmI
方法。
结论
在本教程中,您使用了 ViewChild
来从父组件类中访问指令、子组件和 DOM 元素。
如果引用动态更改为新元素,ViewChild
将自动更新其引用。
在需要访问多个子元素的情况下,您应该使用 ViewChildren
。
如果您想了解更多关于 Angular 的知识,请查看我们的 Angular 专题页面,了解练习和编程项目。