angular组件通信

官网:https://angular.cn/guide/component-interaction


1、父组件 向 子组件 传递数据:Input

父组件中改变某变量X(任何数据类型), 子组件用 @Input 接收该变量

父组件:

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

子组件:

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

如果传入子组件的数据,仅仅在子组件中用来显示,是不需考虑输入变化的(双向绑定就帮我们自动实现了),而往往还要在input变化时做一些逻辑处理,此时就需要对输入属性的变化进行监听,通常有两种方式:

方法1: 通过 setter 截听输入属性值的变化

针对一个输入属性,设置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) {
     // 当父组件输入的name变化的时候,set方法自动截听,然后在这里做相应的处理
    // 入参name就是最新的值,而当前旧值就是本地私有变量_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() 方法来监测所有输入属性值的变化并做出回应。

当需要监视多个、交互式输入属性的时候,本方法比用属性的 setter 更合适。

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

**setter vs ngOnChanges

如果要对某个输入变量进行变化监听,setter好用

如果多个输入变量都需要进行变化监听,并且在监听后的逻辑处理涉及到多个输入属性,ngOnChanges好用 -- 可以在这个方法中统一处理

2、子组件 向 父组件 传递数据: Output EventEmitter

首先子组件暴露一个 EventEmitter 属性,当子组件中改变某变量X(任何数据类型),或者想要传递消息,子组件就利用EventEmitter属性的emit方法,将事件发射出去, 父组绑定该事件,并定义相应的方法做出响应

子组件:

Output() childEmit: EventEmitter<T> = new EventEmitter<T>();
// 对某变量data一顿操作后,发射出去
this.childEmit.emit(data);</pre>

父组件:

在子组件引用上面绑定:(eventEmitter)="模板表达式",就像响应(click)事件一样。

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

3、父组件 访问 子组件: 本地变量

在父组件模板里,新建一个本地变量来代表子组件(其实就是子组件的引用),然后利用这个变量来读取子组件的属性和调用子组件的方法, 比较方便实用

父组件:

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

<span>{{ grid.name }}</span> // 直接获取子组件变量

<button (click)="grid.func()">直接调用子组件方法</button></pre>

这个本地变量方法简单便利,但是它也有局限性:父组件-子组件的连接必须全部在父组件的模板中进行。父组件本身的代码对子组件没有访问权。即,仅限于在html代码中操作

4、父组件 访问 子组件: ViewChild 方法

如果父组件的需要读取子组件的属性值或调用子组件的方法,就不能使用本地变量方法。当父组件需要这种访问时,可以把子组件作为 ViewChild注入到父组件里面。

父组件:

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

<span>{{ grid.name }}</span> // 直接获取子组件变量

<button (click)="grid.func()">直接调用子组件方法</button></pre>
 @ViewChild('grid') grid: BaseGridComponent; // 表格
// 我还可以干些别的
this.grid  巴拉巴拉</pre>

5、非父子组件通信: service 实例共享

组件之间共享同一个服务实例,利用该服务在组件之间实现双向通讯。其实就是服务实例的一个变量,在引用服务的各个组件中都可以被改变和读取

服务:

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,  // 引用服务
) { }

public changeInfo():void {
  this.service.info = this.service.info + '1234';   // 写数据
}

组件 2 从 service 获取信息

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

public constructor(
  public service: Service2, // 引用服务
) { }

public showInfo() {
  console.log(this.service.info);   // 读取数据
}

6、非父子组件通信: Subject(发布订阅)

发布订阅模式,当发布者数据改变时,订阅者也能得到及时响应

1、定义事件

 @Injectable()
export class AppService {
  // 开立诊断,诊断更新后通知,需要的地方注册监听
  afterDiagnosticUpdate: EventEmitter<'ADD' | 'DELETE' | 'INVALID'>;

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

1、在发布事件的组件中进行 emit() :发出包含给定值的事件。

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

2、在需要知道该事件的组件中进行订阅 subscribe():即注册此实例发出的事件的处理器。

 // 注册监听器(消息订阅者)
this.msgReader = this.appService.afterDiagnosticUpdate.subscribe((opt: string) => {
  // 监听后的处理
  doSomething......
});

// 组件销货时,注销监听器
ngOnDestroy(): void {
  this.msgReader.unsubscribe();
}

重要:虽然监听器是在组件中定义并创建,但是组件销毁时,监听器并未自动销毁,需要调用unsubscribe 来执行销货。 这个非常重要,否则轻则内存泄露,重则导致逻辑出现异常(逻辑处理在一个已经死掉的组件中执行,并且执行结果有效)。

7、路由传参通信

1、 查询参数中传递数据

在a标签上添加一个参数queryParams,接收要传入的参数对象

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

在跳转后进入的页面(组件),注入ActivatedRoute, 用通过对queryParams订阅的方式,来接收传递来的参数:

   constructor( private activatedRoute: ActivatedRoute) {}
    ngOnInit() {
        this.activatedRoute.queryParams.subscribe(params => {
            // 接收参数
            this.id = params.id;
        });
    }

2、 路由路径(url)中传递参数

修改路由配置文件path还是以tab4组件为例:

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

我们在后面添加/:name,name即为传递的参数名

a标签设置如下,routerLink后面数组的第二个参数为传递的参数值

<a [routerLink]="['/tab4','我是url传递参数']" [queryParams]="{id:3}" >tab4</a></pre>

在跳转后进入的页面(组件),注入ActivatedRoute, 用通过对params订阅的方式,来接收传递来的参数(注意和1对比):

  constructor( private activatedRoute: ActivatedRoute) {}
    ngOnInit() {
        this.activatedRoute.params.subscribe(params => {
            // 接收参数
            this.name = params.name;
        });
    }

也可以这样写(**snapshot透过快照的方式获取值 **)

( private activatedRoute: ActivatedRoute) {}
    ngOnInit() {
        // 接收参数
        this.name = this.activatedRoute.snapshot.params['name']
    }

snapshot快照和subscribe订阅差别在于:订阅实时监视着数据的变化,而快照只在调用时改变一次,如果在确定路由参数只在组件初次创建时获取一次可以采用快照,如需组件内路由参数可能实时变化,则采取订阅

3、 路由配置中设置静态数据

修改路由配置文件path还是以tab4组件为例:

  {
    path: 'tab4/:name',
    component:Tab4Component,
    children: [],
    data:[{Data:'路由配置静态数据'}]
  }

tab4组件中获取并赋值数据

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"]
  }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容