Angular8 組件通信基礎使用場景(一)

組件交互

父子組件交互(常見)

輸入輸出屬性 Input,Outputcss

最基礎的場景之一,使用很是普遍。使用方法,將父組件中的數據與子組件聲明的變量進行綁定,保證子組件能夠用於內部渲染模板,主要關注下子組件內部代碼格式:html

import { Component, OnInit, Input } from '@angular/core';
@Component({
  selector: 'app-children',
  templateUrl: './children.component.html',
  styleUrls: ['./children.component.scss']
})
export class ChildrenComponent implements OnInit {
  @Input() List: Array<any>;
  constructor() { }
  ngOnInit() {
  }
}

經過@Input 裝飾器來聲明這個變量是個輸入屬性,用於像dom那樣綁定屬性同樣使用,可是有點區別:數組

當前總記錄條數:{{dataList.length}}
<app-children [List]="dataList"></app-children>

用 [ ] 符號與當前組件或者頁面中的數據進行綁定。這種場景數據傳輸方向比較單1、簡單,實際開發中更多的是子組件也會操做部分數據,父組件也要時刻接收到變化。
在Angular中,子組件傳播事件須要從@angular/core中引入EventEmitter類,demo以下:app

//組件內代碼
@Output () removeHandler = new EventEmitter();
//組件模板中操做事件
removeAll(){
    this.List = [];
    this.removeHandler.emit(數據或者事件名稱);
}

模板:dom

<h4>子組件顯示錶格:</h4>
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Phone</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let item of List">
      <td>{{item.name}}</td>
      <td>{{item.phone}}</td>
    </tr>
  </tbody>
</table>
<button (click)="removeAll()">清空所有</button>

父組件:ide

<app-children (removeHandler)="removeData($event)" [List]="dataList"></app-children>
removeData(e) {
    console.log(e);
    this.dataList = e; //如何將數據更新到本組件根據場景實現
  }

onChanges 生命週期截聽輸入屬性變化函數

除此以外,官方demo中還提供了2種截聽輸入值的變化來更新本地數據,一種是對子組件綁定的屬性進行getter和setter處理;另一種用的蠻多的在開發中,利用組件的聲明週期鉤子 ngOnChanges 函數進行處理,上述demo我做下修改,子組件:this

export class ChildrenComponent implements OnInit, OnChanges {
  @Input() List: Array<any>;
  changeList = [];
  @Output() removeHandler = new EventEmitter();
  constructor() { }
  ngOnInit() {

  }
  ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
    let logs = [];
    if (!changes.List.firstChange) {
      logs = changes.List.currentValue;
      this.changeList = logs;
    }
  }
  removeAll() {
    this.changeList = [];
    this.removeHandler.emit(this.changeList);
  }
}
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Phone</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let item of changeList">
      <td>{{item.name}}</td>
      <td>{{item.phone}}</td>
    </tr>
  </tbody>
</table>
<button (click)="removeAll()">清空所有</button>

注意,本案例因我只綁定了一個輸入屬性,若是是多個,應當使用for循環更新指定的數據。code

本地變量互動component

官方定義:

父組件不能使用數據綁定來讀取子組件的屬性或調用子組件的方法。但能夠在父組件模板裏,新建一個本地變量來表明子組件,而後利用這個變量來讀取子組件的屬性和調用子組件的方法

子組件修改;

export class ChildrenComponent implements OnInit {
  // @Input() List: Array<any>;
  changeList = [];
  // @Output() removeHandler = new EventEmitter();
  constructor() { }
  ngOnInit() {

  }
  addData(data) {
    this.changeList = [...this.changeList, data];
  }
  removeAll() {
    this.changeList = [];
  }
}

html模板不變;
父組件:

<h4>新增一條記錄</h4>
<div class="basic-data">
  <label>name:</label>
  <input type="text" name="name" [(ngModel)]="name">
  <label>phone:</label>
  <input type="text" name="phone" [(ngModel)]="phone">
  <button (click)="table.addData({name:name,phone:phone})">添加</button>
  <button (click)="table.removeAll()">清除</button>
</div>
當前總記錄條數:{{table.changeList.length}}
<app-children #table></app-children>
export class BasicComponent implements OnInit {

  constructor() { }
  name = '';
  phone = '';
  ngOnInit() {

  }
}

組件內邏輯均刪除,由於經過綁定的 #table 能夠直接訪問子組件屬性和方法。

父組件調用@ViewChild

某些時候咱們須要在組件中直接訪問子組件內屬性和方法,本地變量就不適用了,能夠考慮使用 @ViewChild()

父組件修改:

<h4>新增一條記錄</h4>
<div class="basic-data">
  <label>name:</label>
  <input type="text" name="name" [(ngModel)]="name">
  <label>phone:</label>
  <input type="text" name="phone" [(ngModel)]="phone">
  <button (click)="addData()">添加</button>
  <button (click)="removeAll()">清除</button>
</div>
當前總記錄條數:{{dataList.length}}
<app-children></app-children>
import { Component, OnInit, ViewChild } from '@angular/core';
import { ChildrenComponent } from '../children/children.component';
@Component({
  selector: 'app-basic',
  templateUrl: './basic.component.html',
  styleUrls: ['./basic.component.scss']
})
export class BasicComponent implements OnInit {
  @ViewChild(ChildrenComponent, { static: false })
  private children: ChildrenComponent;
  constructor() { }
  name = '';
  phone = '';
  dataList = [];
  ngOnInit() {

  }
  addData() {
    this.dataList = [...this.dataList, {
      name: this.name,
      phone: this.phone
    }];
    this.children.addData({
      name: this.name,
      phone: this.phone
    });
  }
  removeAll() {
    this.dataList = [];
    this.children.removeAll();
  }
}

若是子組件內有初始化操做的能夠在父組件的AfterViewInit聲明週期中初始化。

任意組件之間-服務(Service)

業務中比較多的交互每每不存在父子組件的關聯,這時候使用服務交互是個不錯的選擇。

服務文件代碼:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class WorkerListService {
  workList = [];
  workListSource = new Subject<any>();
  private workListSource$ = this.workListSource.asObservable();
  constructor() { }
  addInfo(info) {
    this.workList = [...this.workList, info];
    this.workListSource.next(this.workList);
  }
  updateWorkList(infos: Array<any>) {
    this.workList = infos;
    this.workListSource.next(this.workList);
  }

}

解釋下代碼部分,首先一個數據能夠被訂閱的前提必須是一個Observable類型,對於普通數組 of(SomeArray) 已是一個Observable類型能夠訂閱,對於返回的http請求也是個Observable類型,在頁面中能夠直接訂閱處理,在Ng官方文檔有列舉Observable類型的說明,瞭解更多能夠前往查看,next() 方法告知這個可觀察對象更新內容,這樣你的訂閱(subscribe)纔會抓取到更新後的信息。

原父組件:

import { Component, OnInit } from '@angular/core';
import { WorkerListService } from '../worker-list.service';
@Component({
  selector: 'app-basic',
  templateUrl: './basic.component.html',
  styleUrls: ['./basic.component.scss']
})
export class BasicComponent implements OnInit {
  constructor(
    private workListService: WorkerListService
  ) { }
  name = '';
  phone = '';
  dataList = [];
  ngOnInit() {
    this.workListService.workListSource.subscribe(res => {
      this.dataList = res;
    });
  }
  addData() {
    this.workListService.addInfo({
      name: this.name,
      phone: this.phone
    });
  }
  removeAll() {
    this.dataList = [];
    this.workListService.updateWorkList(this.dataList);
  }
}

原子組件:

import { Component, OnInit } from '@angular/core';
import { WorkerListService } from '../worker-list.service';
@Component({
  selector: 'app-children',
  templateUrl: './children.component.html',
  styleUrls: ['./children.component.scss']
})
export class ChildrenComponent implements OnInit {
  changeList = [];
  constructor(
    private workListService: WorkerListService
  ) {
    this.workListService.workListSource.subscribe(res=>{
      this.changeList = res;
    });
  }
  ngOnInit() {

  }
}

這樣就能夠保證組件能夠隨時獲取到最新的數據更新,而不用擔憂是否爲父子級組件,也是最經常使用的方式。

相關文章
相關標籤/搜索