手记

获取模板元素

基本概念

Angular 内置了 ViewChild 和 ViewChildren 装饰器来获取模板中匹配到的元素或指令。
在 ngAfterViewInit 钩子函数中才能够查看获取到的元素或指令。

*ngAfterViewInit:组件视图初始化之后调用。

ViewChild

获取模板中匹配到的第一个元素或指令。

1、获取原生 DOM 元素

通过模板引用变量来获取原生 DOM 元素。

例子:

// app.component.html
<section>
  <p #text>hello</p>
</section>

// app.component.ts
// 引入装饰器 ViewChild 和接口 ElementRef
import { Component, AfterViewInit, ViewChild, ElementRef} from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent implements AfterViewInit {

  // 取到变量 text,类型为 ElementRef
  @ViewChild('text')
  txt!:ElementRef;

  constructor() { }

  // 查看获取到的元素
  ngAfterViewInit(){
    console.log(this.txt.nativeElement.innerHTML);
  }
}

ElementRef 是 Angular 封装的一个用于操作原生 DOM 元素的接口,究其原因,是因为 Angular 本身不局限于只在浏览器上运行(比如还有 web workder 环境,不存在 DOM)。因此,Angular 内置了 ElementRef 隔离开应用层与 DOM 层。如果我们需要直接操作 DOM 元素,可以通过 ElementRef 下的 nativeElement 属性。

2、获取组件及其内部属性

获取组件有两种方式,第一种依然是通过模板引用变量:

例子:

// app.component.html
<section>
  <app-my-component #text></app-my-component>
</section>

// app.component.ts
/// 引入装饰器 ViewChild 和子组件 MyComponentComponent
import { Component, AfterViewInit, ViewChild} from '@angular/core';
import { MyComponentComponent } from './components/my-component/my-component.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent implements AfterViewInit {

  // 取到变量 text,类型设置为 MyComponentComponent
  @ViewChild('text')
  txt!:MyComponentComponent; // 类型为 any 也可以

  constructor( ) { }

  // 查看获取到的元素
  // welcome 为子组件的属性,可以直接使用
  ngAfterViewInit(){
    console.log(this.txt.welcome);
  }
}

第二种是通过组件类:

// 如果不使用模板引用变量
// 直接引入组件 MyComponentComponent 也可以
// 如下写法:
@ViewChild(MyComponentComponent)
txt!:MyComponentComponent;

3、获取指令

通过模板引用变量来获取 ng-template 指令的内容在《模板引用变量》已经详细介绍过,在此就不再赘述。

设置查询条件

ViewChild 可以选择性设置第二个参数 read,用来增加查询条件。但这个参数不是必需的,因为 Angular 会根据即将返回的类型自动添加查询条件,比如将要返回的是原生 DOM 元素,那么查询类型就是 ElementRef,如果将要返回的是内嵌模板 ng-template,那么查询类型就 TemplateRef,再比如我们上个例子中,将要返回的是子组件将 MyComponentComponent,那么默认的查询类型就是MyComponentComponent

例子:

// html
<section>
  <app-my-component #text></app-my-component>

  <ng-template #name>
    <p>Tom</p>
  </ng-template>

  <p #age>20</p>
</section>

// ts
import { Component, AfterViewInit, ViewChild, ElementRef, TemplateRef } from '@angular/core';

@ViewChild('text',{read: MyComponentComponent})
txt!:MyComponentComponent;

@ViewChild('name',{read:TemplateRef})
name!:TemplateRef<any>;

@ViewChild('age',{read:ElementRef})
age!:ElementRef;

ngAfterViewInit(){
  console.log(this.txt);
  console.log(this.name);
  console.log(this.age);
}

上面例子中,不添加查询条件,返回的结果是一样的:

例子:

@ViewChild('text')
txt!:MyComponentComponent;

@ViewChild('name')
name!:TemplateRef<any>;

@ViewChild('age')
age!:ElementRef;

但是,ViewContainerRef 类型不能被 Angular 推断出来,需要手动添加查询条件。

例子:

// html
<section>
  <ng-template #name>
    <p>Tom</p>
  </ng-template>

  <p #age>20</p>
</section>

// ts
import { Component, AfterViewInit, ViewChild, ElementRef, TemplateRef ,ViewContainerRef} from '@angular/core';

@ViewChild('name')
name!:TemplateRef<any>;

@ViewChild('name',{read:ViewContainerRef})
nameActive!:ViewContainerRef;

@ViewChild('age',{read:ViewContainerRef})
age!:ViewContainerRef;

ngAfterViewInit(){
  this.nameActive.createEmbeddedView(this.name);
  this.age.createEmbeddedView(this.name);
}

ViewChildren

获取模板中匹配到的多个元素或指令,返回一个 QueryList 集合。

例子:

// html
<section>
  <app-my-component #text></app-my-component>

  <ng-template #text>
    <p>Tom</p>
  </ng-template>
  
  <p #text>20</p>
</section>

// ts
import { Component, AfterViewInit, ViewChildren, QueryList} from '@angular/core';

@ViewChildren('text')
txt!:QueryList<any>;

ngAfterViewInit(){
  if (this.txt != null && this.txt.length !== 0) {
    this.txt.forEach(el => console.log(el));
  }
}

end

0人推荐
随时随地看视频
慕课网APP