如何在 Angular 中使用 ViewChild 访问子组件、指令或 DOM 元素

简介

本文将向您介绍Angular的ViewChild装饰器。

在某些情况下,您可能希望访问父组件类中的指令、子组件或DOM元素。ViewChild修饰符返回与给定指令、组件或模板引用选择器匹配的第一个元素。

前提条件

如果您想跟随本教程学习,请执行以下操作:

  • 考虑安装@angular/cli.
  • 使用@angular/cli创建一个新项目,在其中测试ViewChild功能。

本教程已通过@angular/corev13.0.2和@angular/cliv13.0.3进行验证。

在指令中使用ViewChild

ViewChild使访问指令成为可能。

假设您有一个SharkDirective。该指令将查找具有属性appShark的元素,并在元素中的文本前面加上单词Shark

理想情况下,您将使用@angular/cli生成您的指令:

1ng generate directive shark --skip-tests

此命令将创建一个Shark.Directive.ts文件。并将指令添加到app.mode.ts中:

 1[label app.module.ts]
 2import { SharkDirective } from './shark.directive';
 3...
 4@NgModule({
 5  declarations: [
 6    AppComponent,
 7    SharkDirective
 8  ],
 9  ...
10})

然后使用ElementRefRenderer2重写文本。将Shark.Directive.ts的内容替换为:

 1[label shark.directive.ts]
 2import {
 3  Directive,
 4  ElementRef,
 5  Renderer2
 6} from '@angular/core';
 7
 8@Directive(
 9  { selector: '[appShark]' }
10)
11export class SharkDirective {
12  creature = 'Dolphin';
13
14  constructor(elem: ElementRef, renderer: Renderer2) {
15    let shark = renderer.createText('Shark ');
16    renderer.appendChild(elem.nativeElement, shark);
17  }
18}

接下来,在组件模板中包含文本的span中添加一个appShark属性。将app.Component.html的内容替换为:

1[label app.component.html]
2<span appShark>Fin!</span>

在浏览器中查看应用程序时,它会在元素内容之前呈现单词Shark

1[secondary_label Output]
2Shark Fin!

现在,您还可以访问SharkDirectivecreature实例变量,并使用其值设置extraCreature实例变量。将app.component.ts的内容替换为以下内容:

 1[label app.component.ts]
 2import {
 3  Component,
 4  ViewChild,
 5  AfterViewInit
 6} from '@angular/core';
 7import { SharkDirective } from './shark.directive';
 8
 9@Component({
10  selector: 'app-root',
11  templateUrl: './app.component.html',
12  styleUrls: ['./app.component.css']
13})
14export class AppComponent implements AfterViewInit {
15  extraCreature!: string;
16
17  @ViewChild(SharkDirective)
18  set appShark(directive: SharkDirective) {
19    this.extraCreature = directive.creature;
20  };
21
22  ngAfterViewInit() {
23    console.log(this.extraCreature); // Dolphin
24  }
25}

这段代码使用了一个setter来设置Extra Creature变量。请注意,它等待AfterViewInit生命周期hook访问变量,因为这是子组件和指令可用的时候。

在浏览器中查看应用程序时,您仍会看到Shark Fin!消息。但是,在控制台日志中,它将显示:

1[secondary_label Output]
2Dolphin

父组件能够访问指令中的值。

结合使用ViewChild和DOM元素

通过ViewChild可以访问具有模板引用变量的原生DOM元素。

假设您的模板中有一个<INPUT>,引用变量为# ome Input。将app.Component.html的内容替换为:

1[label app.component.html]
2<input #someInput placeholder="Your favorite sea creature">

现在,您可以通过ViewChild访问<input>,并设置value。将app.Component.ts的内容替换为:

 1[label app.component.ts]
 2import {
 3  Component,
 4  ViewChild,
 5  AfterViewInit,
 6  ElementRef
 7} from '@angular/core';
 8
 9@Component({
10  selector: 'app-root',
11  templateUrl: './app.component.html',
12  styleUrls: ['./app.component.css']
13})
14export class AppComponent implements AfterViewInit {
15  @ViewChild('someInput') someInput!: ElementRef;
16  ngAfterViewInit() {
17    this.someInput.nativeElement.value = 'Whale!';
18  }
19}

ngAfterViewInit触发时,<input>的值将被设置为:

1[secondary_label Output]
2Whale!

父组件能够设置子DOM元素的值。

对子组件使用ViewChild

ViewChild使访问子组件和调用方法或访问子组件可用的实例变量成为可能。

假设您有一个‘PupComponent’。

理想情况下,您可以使用@angular/cli生成您的组件:

1ng generate component pup --flat --skip-tests

该命令将创建pup.Component.tspup.Component.csspup.Component.html文件。并将组件添加到app.mode.ts中:

 1[label app.module.ts]
 2import { PupComponent } from './pup.component';
 3...
 4@NgModule({
 5  declarations: [
 6    AppComponent,
 7    PupComponent
 8  ],
 9  ...
10})

然后,在PupComponent中添加一个walAmI方法,该方法返回一条消息:

 1[label pup.component.ts]
 2import { Component, OnInit } from '@angular/core';
 3
 4@Component({
 5  selector: 'app-pup',
 6  templateUrl: './pup.component.html',
 7  styleUrs: ['./pup/component.css']
 8})
 9export class PupComponent implements OnInit {
10
11  constructor() { }
12
13  whoAmI() {
14    return 'I am a pup component!';
15  }
16
17  ngOnInit(): void {
18  }
19
20}

接下来,引用应用程序模板中的子组件。将app.Component.html的内容替换为:

1[label app.component.html]
2<app-pup>pup works!</app-pup>

现在,您可以使用ViewChild从父组件类中调用whAmI方法。将app.Component.ts的内容替换为:

 1[label app.component.ts]
 2import {
 3  Component,
 4  ViewChild,
 5  AfterViewInit
 6} from '@angular/core';
 7import { PupComponent } from './pup.component';
 8
 9@Component({
10  selector: 'app-root',
11  templateUrl: './app.component.html',
12  styleUrls: ['./app.component.css'],
13})
14export class AppComponent implements AfterViewInit {
15  @ViewChild(PupComponent) pup!: PupComponent;
16  ngAfterViewInit() {
17    console.log(this.pup.whoAmI()); // I am a pup component!
18  }
19}

在浏览器中查看应用程序时,控制台日志将显示:

1[secondary_label Output]
2I am a pup component!

父组件能够调用子组件的everAmI方法。

结论

在本教程中,您使用ViewChild来访问父组件类中的指令、子组件和DOM元素。

如果引用动态更改为新元素,则ViewChild会自动更新其引用。

如果要访问多个子对象,则应改用ViewChildren

如果您想了解更多有关ANGLE的信息,请查看我们的ANGLE主题页面以获取练习和编程项目。

Published At
Categories with 技术
Tagged with
comments powered by Disqus