angular組件通信

官網(wǎng):https://angular.cn/guide/component-interaction


1、父組件 向 子組件 傳遞數(shù)據(jù):Input

父組件中改變某變量X(任何數(shù)據(jù)類型), 子組件用 @Input 接收該變量

父組件:

<!-- parentComponent -->
<app-child [name]="'childName'"></app-child>

子組件:

@Input() public name:string = '';

如果傳入子組件的數(shù)據(jù),僅僅在子組件中用來顯示,是不需考慮輸入變化的(雙向綁定就幫我們自動實現(xiàn)了),而往往還要在input變化時做一些邏輯處理,此時就需要對輸入屬性的變化進行監(jiān)聽,通常有兩種方式:

方法1: 通過 setter 截聽輸入屬性值的變化

針對一個輸入屬性,設(shè)置setter,以攔截父組件中值的變化,并采取行動。

更多知識:https://my.oschina.net/sunlightday/blog/3118148

子組件:

import { Component, Input } from '@angular/core';

 @Component({
   selector: 'app-name-child',
   template: '<h3>"{{name}}"</h3>'
 })
 export class NameChildComponent {
   @Input()
   get name(): string { return this._name; }
   set name(name: string) {
     // 當(dāng)父組件輸入的name變化的時候,set方法自動截聽,然后在這里做相應(yīng)的處理
    // 入?yún)ame就是最新的值,而當(dāng)前舊值就是本地私有變量_name     this._name = (name && name.trim()) || '<no name set>';
   }
  private _name = '';
 }</pre>

父組件:

import { Component } from '@angular/core';
 
 @Component({
   selector: 'app-name-parent',
   template: ` 
    <h2>Master controls {{names.length}} names</h2>
   <app-name-child *ngFor="let name of names" [name]="name"></app-name-child>
   `
 })
 export class NameParentComponent {
   // Displays 'Dr IQ', '<no name set>', 'Bombasto'
   names = ['Dr IQ', '   ', '  Bombasto  '];
 }

方法2: 通過ngOnChanges()來截聽輸入屬性值的變化

使用 OnChanges 生命周期鉤子接口的 ngOnChanges() 方法來監(jiān)測所有輸入屬性值的變化并做出回應(yīng)。

當(dāng)需要監(jiān)視多個、交互式輸入屬性的時候,本方法比用屬性的 setter 更合適。

生命周期鉤子:https://angular.cn/guide/lifecycle-hooks

**setter vs ngOnChanges

如果要對某個輸入變量進行變化監(jiān)聽,setter好用

如果多個輸入變量都需要進行變化監(jiān)聽,并且在監(jiān)聽后的邏輯處理涉及到多個輸入屬性,ngOnChanges好用 -- 可以在這個方法中統(tǒng)一處理

2、子組件 向 父組件 傳遞數(shù)據(jù): Output EventEmitter

首先子組件暴露一個 EventEmitter 屬性,當(dāng)子組件中改變某變量X(任何數(shù)據(jù)類型),或者想要傳遞消息,子組件就利用EventEmitter屬性的emit方法,將事件發(fā)射出去, 父組綁定該事件,并定義相應(yīng)的方法做出響應(yīng)

子組件:

Output() childEmit: EventEmitter<T> = new EventEmitter<T>();
// 對某變量data一頓操作后,發(fā)射出去
this.childEmit.emit(data);</pre>

父組件:

在子組件引用上面綁定:(eventEmitter)="模板表達式",就像響應(yīng)(click)事件一樣。

<app-child (childEmit)="getData($event)"></app-child></pre>

3、父組件 訪問 子組件: 本地變量

在父組件模板里,新建一個本地變量來代表子組件(其實就是子組件的引用),然后利用這個變量來讀取子組件的屬性和調(diào)用子組件的方法, 比較方便實用

父組件:

<app-base-grid #grid></app-base-grid>

<span>{{ grid.name }}</span> // 直接獲取子組件變量

<button (click)="grid.func()">直接調(diào)用子組件方法</button></pre>

這個本地變量方法簡單便利,但是它也有局限性:父組件-子組件的連接必須全部在父組件的模板中進行。父組件本身的代碼對子組件沒有訪問權(quán)。即,僅限于在html代碼中操作

4、父組件 訪問 子組件: ViewChild 方法

如果父組件的需要讀取子組件的屬性值或調(diào)用子組件的方法,就不能使用本地變量方法。當(dāng)父組件需要這種訪問時,可以把子組件作為 ViewChild注入到父組件里面。

父組件:

<app-base-grid #grid></app-base-grid>

<span>{{ grid.name }}</span> // 直接獲取子組件變量

<button (click)="grid.func()">直接調(diào)用子組件方法</button></pre>
 @ViewChild('grid') grid: BaseGridComponent; // 表格
// 我還可以干些別的
this.grid  巴拉巴拉</pre>

5、非父子組件通信: service 實例共享

組件之間共享同一個服務(wù)實例,利用該服務(wù)在組件之間實現(xiàn)雙向通訊。其實就是服務(wù)實例的一個變量,在引用服務(wù)的各個組件中都可以被改變和讀取

服務(wù):

import { Component, Injectable, EventEmitter } from '@angular/core';

@Injectable()
export class myService {
  public info: string = '';
}

組件 1 向 service 傳遞信息

import { Service1 } from '../../service/service1.service';


public constructor(
  public service: Service1,  // 引用服務(wù)
) { }

public changeInfo():void {
  this.service.info = this.service.info + '1234';   // 寫數(shù)據(jù)
}

組件 2 從 service 獲取信息

import { Service2 } from '../../service/service2.service';

public constructor(
  public service: Service2, // 引用服務(wù)
) { }

public showInfo() {
  console.log(this.service.info);   // 讀取數(shù)據(jù)
}

6、非父子組件通信: Subject(發(fā)布訂閱)

發(fā)布訂閱模式,當(dāng)發(fā)布者數(shù)據(jù)改變時,訂閱者也能得到及時響應(yīng)

1、定義事件

 @Injectable()
export class AppService {
  // 開立診斷,診斷更新后通知,需要的地方注冊監(jiān)聽
  afterDiagnosticUpdate: EventEmitter<'ADD' | 'DELETE' | 'INVALID'>;

  constructor() {
    this.afterDiagnosticUpdate = new EventEmitter();
  }
}

1、在發(fā)布事件的組件中進行 emit() :發(fā)出包含給定值的事件。

this.appService.afterDiagnosticUpdate.emit('ADD');

2、在需要知道該事件的組件中進行訂閱 subscribe():即注冊此實例發(fā)出的事件的處理器。

 // 注冊監(jiān)聽器(消息訂閱者)
this.msgReader = this.appService.afterDiagnosticUpdate.subscribe((opt: string) => {
  // 監(jiān)聽后的處理
  doSomething......
});

// 組件銷貨時,注銷監(jiān)聽器
ngOnDestroy(): void {
  this.msgReader.unsubscribe();
}

重要:雖然監(jiān)聽器是在組件中定義并創(chuàng)建,但是組件銷毀時,監(jiān)聽器并未自動銷毀,需要調(diào)用unsubscribe 來執(zhí)行銷貨。 這個非常重要,否則輕則內(nèi)存泄露,重則導(dǎo)致邏輯出現(xiàn)異常(邏輯處理在一個已經(jīng)死掉的組件中執(zhí)行,并且執(zhí)行結(jié)果有效)。

7、路由傳參通信

1、 查詢參數(shù)中傳遞數(shù)據(jù)

在a標(biāo)簽上添加一個參數(shù)queryParams,接收要傳入的參數(shù)對象

<a [routerLink]="['/tab4']" [queryParams]="{id:3}" >tab4</a></pre>

在跳轉(zhuǎn)后進入的頁面(組件),注入ActivatedRoute, 用通過對queryParams訂閱的方式,來接收傳遞來的參數(shù):

   constructor( private activatedRoute: ActivatedRoute) {}
    ngOnInit() {
        this.activatedRoute.queryParams.subscribe(params => {
            // 接收參數(shù)
            this.id = params.id;
        });
    }

2、 路由路徑(url)中傳遞參數(shù)

修改路由配置文件path還是以tab4組件為例:

 {
    path: 'tab4/:name',
    component:Tab4Component,
    children: []
  },

我們在后面添加/:name,name即為傳遞的參數(shù)名

a標(biāo)簽設(shè)置如下,routerLink后面數(shù)組的第二個參數(shù)為傳遞的參數(shù)值

<a [routerLink]="['/tab4','我是url傳遞參數(shù)']" [queryParams]="{id:3}" >tab4</a></pre>

在跳轉(zhuǎn)后進入的頁面(組件),注入ActivatedRoute, 用通過對params訂閱的方式,來接收傳遞來的參數(shù)(注意和1對比):

  constructor( private activatedRoute: ActivatedRoute) {}
    ngOnInit() {
        this.activatedRoute.params.subscribe(params => {
            // 接收參數(shù)
            this.name = params.name;
        });
    }

也可以這樣寫(**snapshot透過快照的方式獲取值 **)

( private activatedRoute: ActivatedRoute) {}
    ngOnInit() {
        // 接收參數(shù)
        this.name = this.activatedRoute.snapshot.params['name']
    }

snapshot快照和subscribe訂閱差別在于:訂閱實時監(jiān)視著數(shù)據(jù)的變化,而快照只在調(diào)用時改變一次,如果在確定路由參數(shù)只在組件初次創(chuàng)建時獲取一次可以采用快照,如需組件內(nèi)路由參數(shù)可能實時變化,則采取訂閱

3、 路由配置中設(shè)置靜態(tài)數(shù)據(jù)

修改路由配置文件path還是以tab4組件為例:

  {
    path: 'tab4/:name',
    component:Tab4Component,
    children: [],
    data:[{Data:'路由配置靜態(tài)數(shù)據(jù)'}]
  }

tab4組件中獲取并賦值數(shù)據(jù)

private data
  ngOnInit() {
    // this.id=this.activatedRoute.snapshot.queryParams["id"]
    // this.name=this.activatedRoute.snapshot.params['name']
    this.activatedRoute.queryParams.subscribe((params:Params)=>{
      this.id=params['id']
    })
    this.activatedRoute.params.subscribe((params:Params)=>{
      this.name=params['name']
    })
    //下面為新加入的
    this.data=this.activatedRoute.snapshot.data[0]["Data"]
  }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容