輸入輸出屬性 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() { } }
這樣就能夠保證組件能夠隨時獲取到最新的數據更新,而不用擔憂是否爲父子級組件,也是最經常使用的方式。