angular @viewchild/childen訪問DOM、組件和指令

1 背景

使用公司前端組件庫時,用到了@viewchild,一臉懵逼,場景就是通過模板引用變量獲取了對應的模板實例及其對應的ts實例。經過學習,發現,@ViewChild和@ViewChildren是Angular提供給我們的裝飾器,用於從模板視圖中獲取匹配的元素。獲取模板元素的操作是在在父組件鉤子方法ngAfterViewInit調用之前進行的。

2 基本用法

@ViewChild(入參) 變量名:類名;

這個裝飾器的直接目的,就是通過入參來獲得模板背後的某個類實例,通過對獲得類實例進行操作從而實現DOM操作或者其他邏輯。
入參的類型的有:1、模板引用變量名,2、public權限的類名,比如component、directive還有一些組件主動provider出來的類,3、TemplateRef,本質是還是一個類,只是第二種類型的特殊情況,組件是angular自定義的而已。根據兩種情況分別舉兩個例子:
入參是模板引用變量

<!--兩個-->
<my-component #cmp1="myComponent"></my-component>
<my-component #cmp2模板引用變量></my-component>
@ViewChild('cmp1') var1:myComponent;
@ViewChild('cmp2') var2:myComponent;
//一些var1和var2的操作……

入參是類名

//一個模板和組件類定義在一起的一個組件
import {Component, OnInit} from '@angular/core';
import {ChildService} from './child.service';

@Component({
  selector: 'app-child',
  template: `
    <h1>自定義的一個子組件</h1>
  `,
  providers: [
    ChildService
  ]
})
export class ChildComponent implements OnInit {
  constructor(public childService: ChildService) {
  }

  ngOnInit() {
  }

}
<app-child></app-child>
//對html中的app-child對應的類實例和暴露出來的服務類進行使用
@ViewChild(ChildService) service:ChildService;
@ViewChild(ChildComponent ) component:ChildComponent ;
//一些對service和component的操作

入參是TemplateRef
當選擇器是TemplateRef(模板引用)的時候,則會獲取到html裏面所有的ng-template類型的節點。實際例子如下:

  @ViewChild(TemplateRef) template: TemplateRef<any>;
  @ViewChildren(TemplateRef) templateList: QueryList<TemplateRef<any>>;

但是!!!!!TemplateRef也只不過是一類特殊的組件/類而已。

2.1 小結

最本質的!入參直接是一個的模板引用變量名的情況下,能取到的對應的組件實例肯定只有一個,這樣使用即可:

@ViewChild('cmp1') var1:myComponent;var1:myComponent;

入參是是一個class名,比如自己定義的組件class、 組件provider出來的class、TemplateRef等等,這樣使用:

@ViewChild(ChildService) service:ChildService;
@ViewChildren(TemplateRef) templateList: QueryList<TemplateRef<any>>;

使用@ViewChild,按照類型取DOM時,如果存在多個,只取出現的第一個;想全部取到的話,就用@ViewChildren;
所以,本質上,用模板引用變量還是根據類型取DOM,根據適合的場景進行選擇。

3 代碼實踐

先寫了一個自定義組件,MyInputComponent,選擇器是 app-my-input

<p>
  my-input works!
  手動實現一個的輸入框
</p>
<hr>
<mat-form-field>
  <input matInput [placeholder]="placeHolder" [(ngModel)]="inputValue">
</mat-form-field>
import {Component, OnInit} from '@angular/core';

@Component({
  selector: 'app-my-input',
  templateUrl: './my-input.component.html',
  styleUrls: ['./my-input.component.css']
})
export class MyInputComponent implements OnInit {

  public placeHolder: string;
  public inputValue: string;

  constructor() {
  }

  ngOnInit() {
    this.placeHolder = 'Default Holder';
  }

}

暴露出兩個的屬性,讓父組件進行讀取、使用。
在父組件中對這個自定義組件進行調用:

<hr>
<span>模板引用變量 input1</span>
  <app-my-input #input1></app-my-input><br>
  <span>從本組件的屬性中讀取的值爲:{{input1_in_main_component.inputValue}}</span>
<hr>
<span>模板引用變量 input2</span><br>
<app-my-input #input2></app-my-input>
<span>直接從模板引用變量中讀取的值爲:{{input2.inputValue}}</span>
<hr>
<span>模板引用變量 input3</span>
<app-my-input #input3></app-my-input>

<ol>
  <li *ngFor="let eachInput of inputList;">
    {{eachInput.placeHolder}}<br>{{eachInput.inputValue}}
  </li>
</ol>
@ViewChild('input1') input1_in_main_component: MyInputComponent;
@ViewChildren(MyInputComponent) inputList: MyInputComponent[];

想通過viewchild的方式訪問模板引用變量input1的屬性值,並且對得到的實例進行調用,在頁面上進行顯示。
對於模板引用變量input2,可以直接在頁面上訪問、使用其屬性值。
同時,通過ViewChildren實現了對模板頁面上MyInputComponent組件的DOM選取,成功讀取了自定義組件中的屬性placeholder和inputValue的值。
最終,實現效果如下:
實現圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章