Angular 组件交互(父子组件之间的数据传递)

257 阅读2分钟

主要包括开发中常用到的:

  1. 父组件传值给子组件.
  2. 父组件主动获取子组件中的变量、调用子组件的方法。
  3. 子组件传值给父组件.
  4. 通过Service做数据传递

1.父组件传值给子组件

子组件中

  @Input() userName:string = '';
  @Input() age:string = '';

父组件中

 <app-b-page 
    [index]="i"
    [userName]="item.name" >
 </app-b-page>

可以在子组件ngOnChanges方法中监听父组件传递进来的数据变化。

2.父组件主动获取子组件中的变量、调用子组件的方法

1.通过模板引用变量

父组件html中

    <!--调用子组件的方法-->
    <button type="button" (click)="timer.start()">Start</button>
    <!--获取子组件的变量 会根据子组件数据的变化实时刷新-->
    <div class="seconds">{{timer.seconds}}</div>
    <!--使用 # 对组件命名-->
    <app-countdown-timer #timer></app-countdown-timer>

2.通过 @ViewChild()

父组件TS代码中:
头文件中添加 ViewChild

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

通过@ViewChild属性装饰器,将子组件BPageComponent注入到私有属性bpageComponent里面

@ViewChild(BPageComponent) private bpageComponent!: BPageComponent;
//获取子组件属性
this.bpageComponent.userName;
//调用子组件方法
this.bpageComponent.onSaveScore('', '');

3.子组件传值给父组件

需要通过: @Output()EventEmitter

方法如下:

子组件中

声明@Output()

@Output() onChangeMathScores:EventEmitter<string> = new EventEmitter<string>();

触发子组件的某一个事件,然后再事件中使用onChangeMathScores

this.onChangeMathScores.emit(mathScores);

父组件中

TS代码中添加一个接收的方法:

  onChildChange(value:string){
      console.log('value==', value); 
  }

html代码中:

<app-b-page (onChangeMathScores)="onChildChange($event)"></app-b-page>

这样子组件每次执行this.onChangeMathScores.emit(mathScores);父组件都会收到一个value。感觉类似于callback。

4.通过Service做数据传递

通过rxjs实现

主要步骤: 1.创建服务 2.注册服务 3.在需要的地方监听服务内的方法调用 4.在需要的地方调用服务内的方法 5.那么可不可以通过callback实现?

首先创建一个服务

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

@Injectable({
  providedIn: 'root'
})
export class ChangeScoreService {

  constructor() { }
  
  private chineseScoreChangeSource = new Subject<{index:number, score:string}>();

  chineseScoreChange$ = this.chineseScoreChangeSource.asObservable();

  saveChineseScore(value:{index:number, score:string}) {
    this.chineseScoreChangeSource.next(value);
  }
}

注册服务

在需要使用该服务的最上层组件的.ts代码中注册该服务,切记不可重复注册。应该遵循一个模块使用一个服务的原则(我个人这样认为)。

providers:[ChangeScoreService]

监听服务内方法调用

  constructor(private service:ChangeScoreService) { 
    this.service.chineseScoreChange$.subscribe(
      newValue =>{
        console.log("监听到数据变化==", newValue);
        this.users[newValue.index].chineseScore = Number(newValue.score);
      });
  }

调用服务内的方法

 constructor(private service:ChangeScoreService) {
      
  }
  //在需要的时候调用服务内方法触发监听
 onSend(){
   this.service.saveChineseScore({index:this.index,score:chineseScore});
 }

我在想是不是不使用RXjs,在Service中通过callback也能实现数据传递。通过测试确实可行

服务文件中这样写

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


@Injectable({
  providedIn: 'root'
})
export class ChangeScoreService {

  constructor() { }
  //定义一个方法变量
  tempFunc = function name(params:string) {
    
  }
}

在需要监听的地方

    this.service.tempFunc = (temp)=>{
        console.log('callback测试', temp);
    }

在需要传递参数的地方

    this.service.tempFunc('测试通过')

我不知道这种方法有什么弊端。但是通过我测试看来确实代码少了一些,而且使用相对简单。

我还在想既然callback行得通那么我写一个全局的callback,不使用服务,应该可以吧??

确实可以,但是通过查资料发现,Angular中没有真正的“全局变量”。 因为.ts文件都需要引入头文件才能使用里面的方法和变量。这样的话还是通过服务来处理好一点。主要是因为方便管理。