Angular:在元件之间传递资料的4种方式

1. 父元件至子元件: @Input

子元件内的@Input装饰器定义属性,父元件再透过属性繫结(Property Binding)将资料传递给子元件。
ChildComponent

import { Component, OnInit, Input } from '@angular/core';@Component({  selector: 'app-child',  templateUrl: './child.component.html',  styleUrls: ['./child.component.scss']})export class ChildComponent implements OnInit {  @Input() bankName: string;  @Input() accountId: number;  constructor() { }  ngOnInit(): void {  }}

ChildComponent HTML

<p>{{ bankName }}</p><p>{{ accountId }}</p>

ParentComponent

import { Component, OnInit } from '@angular/core';@Component({  selector: 'app-parent',  templateUrl: './parent.component.html',  styleUrls: ['./parent.component.scss']})export class ParentComponent implements OnInit {  bankName = 'ABC Bank';  accountId = 123456789;  constructor() { }  ngOnInit(): void {  }}

ParentComponent HTML

<app-child [bankName]="bankName" [accountId]="accountId"></app-child>

结果:
http://img2.58codes.com/2024/20112573DvzrzqS8xb.png

2. 子元件至父元件:@Output

子元件藉由@Output装饰器定义属性,该属性为EventEmitter实体,可以设定要传送的资料型别,透过事件繫结(Event Binding)通知父元件有事件发生。

ChildComponent

import { Component, OnInit, EventEmitter, Output } from '@angular/core';@Component({  selector: 'app-child',  templateUrl: './child.component.html',  styleUrls: ['./child.component.scss']})export class ChildComponent implements OnInit {  @Output() counterEvt = new EventEmitter<string>();  constructor() { }  ngOnInit(): void { }  counterChange(cal: string) {    this.counterEvt.emit(cal);  }}

ChildComponent HTML

<button (click)="counterChange('add')">加</button><button (click)="counterChange('minus')">减</button>

ParentComponent

import { Component, OnInit } from '@angular/core';@Component({  selector: 'app-parent',  templateUrl: './parent.component.html',  styleUrls: ['./parent.component.scss']})export class ParentComponent implements OnInit {  counter = 0;  constructor() { }  ngOnInit(): void {  }  counterCal(cal: string) {    cal === 'add' ? this.counter++ : this.counter--;  }}

ParentComponent HTML

<p>counter : {{ counter }}</p><app-child (counterEvt)="counterCal($event)"></app-child>

基于元件的维护性与程式的逻辑性,我们只会在子元件送出事件资料(加或减),当父元件接收到事件资料后,真正的实作应该要在父元件完成,而不是在子元件完成。

结果:

3. 子元件至父元件: @ViewChild

以上的方式可以让父元件-子元件传递资料,但还是有限制:父元件无法存取子元件的属性与方法。
这时可以使用‵@ViewChild在父元件建立子元件的实体,让父元件获得子元件的属性与方法。

实作一个简单的timer。

ChildComponent

import { Component, OnInit } from '@angular/core';@Component({  selector: 'app-child',  templateUrl: './child.component.html',  styleUrls: ['./child.component.scss']})export class ChildComponent implements OnInit {  seconds = 0;  timer: any;  constructor() { }  ngOnInit(): void { }  start() {    this.timer = setInterval(() => {      this.seconds++;    }, 1000);  }  stop() {    clearInterval(this.timer);  }}

所有计时逻辑都在子元件中。

ParentComponent

import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';import { ChildComponent } from '../child/child.component';@Component({  selector: 'app-parent',  templateUrl: './parent.component.html',  styleUrls: ['./parent.component.scss']})export class ParentComponent implements OnInit, AfterViewInit {  @ViewChild(ChildComponent) childComponent: ChildComponent;  constructor() { }  ngOnInit(): void {  }  seconds() {    return 0;  }  ngAfterViewInit() {    setTimeout(() => {      this.seconds = () => this.childComponent.seconds;    }, 1000);  }  onStart() {    this.childComponent.start();  }  onStop() {    this.childComponent.stop();  }}

父元件显示秒数。

整个生命週期中,必须在ngAfterViewInit才能取得子元件的实体。

由于我们目前处于Development Mode,为了避免ExpressionChangedAfterItHasBeenCheckedError的问题,所以在ngAfterViewInit使用setTimeout,详细说明之后会另开文章。

ParentComponent HTML

<button (click)="onStart()">start</button><button (click)="onStop()">stop</button><p>{{ seconds() }}</p><app-child></app-child>

结果:

4. 不相关的元件:service

A元件跟B元件,是两个不相关的原件,可以藉由service作为他们之间沟通的媒介。

实作在A元件输入讯息,在B元件同步显示的功能:
DataService

import { Injectable } from '@angular/core';import { Subject } from 'rxjs';@Injectable({  providedIn: 'root'})export class DataService {  msgContent = new Subject<string>();  constructor() { }  setMessage(value: string) {    this.msgContent.next(value);  }  getMessage() {    return this.msgContent.asObservable();  }}

AComponent

import { Component, OnInit } from '@angular/core';import { DataService } from '../data.service';@Component({  selector: 'app-a',  templateUrl: './a.component.html',  styleUrls: ['./a.component.scss']})export class AComponent implements OnInit {  constructor(private dataSvc: DataService) { }  ngOnInit(): void {  }  onMsgChange(message: string) {    this.dataSvc.setMessage(message);  }}

AComponent HTML

input message : <input (keyup)="onMsgChange($event.target.value)">

BComponent

import { Component, OnInit, OnDestroy } from '@angular/core';import { DataService } from '../data.service';import { Subscription } from 'rxjs';@Component({  selector: 'app-b',  templateUrl: './b.component.html',  styleUrls: ['./b.component.scss']})export class BComponent implements OnInit, OnDestroy {  message: string;  subscription: Subscription;  constructor(private dataSvc: DataService) { }  ngOnInit(): void {    this.subscription = this.dataSvc.getMessage().subscribe(val => {      this.message = val;    });  }  ngOnDestroy(): void {    this.subscription.unsubscribe();  }}

BComponent HTML

here is message : <span>{{ message }}</span>

AppComponent HTML

<app-a></app-a><p></p><app-b></app-b>

结果:

参考来源:
Angular:如何在多个组件之间通信


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章