美文网首页
angular组件通信

angular组件通信

作者: 周末不敲键盘 | 来源:发表于2021-04-14 11:44 被阅读0次

    官网: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"]
      }
    

    相关文章

      网友评论

          本文标题:angular组件通信

          本文链接:https://www.haomeiwen.com/subject/disklltx.html