angular组件通信

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


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

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

父组件:



子组件:

@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: '

"{{name}}"

' }) export class NameChildComponent { @Input() get name(): string { return this._name; } set name(name: string) { // 当父组件输入的name变化的时候,set方法自动截听,然后在这里做相应的处理 // 入参name就是最新的值,而当前旧值就是本地私有变量_name this._name = (name && name.trim()) || ''; } private _name = ''; }

父组件:

import { Component } from '@angular/core';
 
 @Component({
   selector: 'app-name-parent',
   template: ` 
    

Master controls {{names.length}} names

` }) export class NameParentComponent { // Displays 'Dr IQ', '', '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 = new EventEmitter();
// 对某变量data一顿操作后,发射出去
this.childEmit.emit(data);

父组件:

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

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

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

父组件:



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

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

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

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

父组件:



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

 @ViewChild('grid') grid: BaseGridComponent; // 表格
// 我还可以干些别的
this.grid  巴拉巴拉

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,接收要传入的参数对象

tab4

在跳转后进入的页面(组件),注入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后面数组的第二个参数为传递的参数值

tab4

在跳转后进入的页面(组件),注入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"]
  }

你可能感兴趣的:(angular组件通信)