Angular 4 x中组件通信方法

666 阅读2分钟

在前端性能优化中有一条较大的条列是“减少交互/请求次数”;

简单的理解就是除了必要的http请求外,不进行请求能够很大程度上提升前端的响应速度以及流畅度; 随着组件化的出现,数据渲染页面已经逐步取代了由jsp到jQ操作DOM的方式;

组件通信,简单翻译为:在不同组件中传递和处理数据的方法;

常见的有父传子,子传父,兄弟通信(同级不相关);

本文介绍的通信方式如下: 1.Input 2.Output 3.子获父实例 4.父获子实例 5.Service层 6.EventEmitter 7.订阅

###1.父→子 input

parent.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  i: any = 0 ;
  constructor(){
    setInterval(() => {
      this.i++;
    }, 1000);
  }
}

parent.html

<div>
  <span>Parent</span>
</div>

<div>
  <child-component [conent]="i"></child-component>
</div>

child.ts

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

@Component({
    selector: 'child-component',
    templateUrl: './child-component.html',
    styleUrls: []
})

export class childComponent {
    @Input() conent: any;
    constructor(){
    }
}

child.html

<div>
  <span>{{conent}}</span>
</div>

image.png

###2.子→父 output

parent.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  sum: any = 0;

  getChildSum(sum: any) {
    this.sum = sum;
  }
}

parent.html

<div>
  <span>Parent</span>
  <span>{{sum}}</span>
</div>

<div>
  <child-component (sendSum)="getChildSum($event)"></child-component>
</div>

child.ts

import {Component, EventEmitter, Output} from '@angular/core';

@Component({
    selector: 'child-component',
    templateUrl: './child-component.html',
    styleUrls: []
})

export class childComponent {
    btn: boolean = true;
    @Output() sendSum: EventEmitter<any> = new EventEmitter();

    sum: any = 0;
    constructor() {
    }
    onStart(): void {
      this.btn = false;
      setInterval(() => {
        this.sendSum.emit(++this.sum);
      }, 1000);
    }

}

child.html

<div>
  <button (click)="onStart()" *ngIf="btn">点击开始</button>
</div>

image.png

###3.子获得父实例

parent.ts


@Component({
  selector: 'page-parent',
  templateUrl: 'parent.html',
})
export class ParentPage {
  i:number = 0;
}

parent.html

<ion-header>
  <ion-navbar>
    <ion-title>Parent</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <h1>parent: {{i}}</h1>
  <page-child></page-child>
</ion-content>

child.ts

import { Component, Input, EventEmitter, Output,Host,Inject,forwardRef } from '@angular/core';
import{ParentPage} from '../parent/parent';
@Component({
  selector: 'page-child',
  templateUrl: 'child.html',
})
export class ChildPage {
    constructor( @Host() @Inject(forwardRef(() => ParentPage)) app: ParentPage) {
        setInterval(() => {
            app.i++;
        }, 1000);
    }
}

child.html

<ion-content padding>
 child 
</ion-content>

image.png

###4.父获得子实例

parent.ts

import {ViewChild, Component } from '@angular/core';
import{ChildPage}from '../child/child';

@Component({
  selector: 'page-parent',
  templateUrl: 'parent.html',
})
export class ParentPage {
  @ViewChild(ChildPage) child:ChildPage;
    ngAfterViewInit() {
        setInterval(()=> {
            this.child.i++;
        }, 1000)
    }
}

parent.html

<ion-header>
  <ion-navbar>
    <ion-title>Parent</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <h1>parent {{i}}</h1>
  <page-child></page-child>
</ion-content>

child.ts

import { Component, Input, EventEmitter, Output,Host,Inject,forwardRef } from '@angular/core';


@Component({
  selector: 'page-child',
  templateUrl: 'child.html',
})
export class ChildPage {
    i:number = 0;
}

child.html

<ion-content padding>
<h2>child {{i}}</h2>
</ion-content>

image.png

###5.service

parent.ts

import { Component } from '@angular/core';
import{myService}from '../child/myService'

@Component({
  selector: 'page-parent',
  templateUrl: 'parent.html',
})
export class ParentPage {

     i:number=0;

   constructor(service:myService) {
        setInterval(()=> {
            service.i++;
        }, 1000)
    }
}

parent.html

<ion-header>
  <ion-navbar>
    <ion-title>Parent</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
   <h1>parent {{i}}</h1>
   <page-child></page-child>
</ion-content>

child.ts

import { Component} from '@angular/core';
import{myService}from "../child/myService"
@Component({
  selector: 'page-child',
  templateUrl: 'child.html',
})
export class ChildPage {
    constructor(public service:myService){
    }
}

child.html

<ion-content padding>
<h2>child {{service.i}}</h2>
</ion-content>

myService.ts ps:记得在app.module.ts 加上providers: [KmyService]

import{Injectable } from '@angular/core';
@Injectable()
export class KmyService {
    i:number = 0;
}

image.png

###6.EventEmitter

myService.ts

import {Component,Injectable,EventEmitter} from '@angular/core';
@Injectable()
export class myService {
    change: EventEmitter<number>;

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

parent.ts

import { Component } from '@angular/core';
import{myService}from '../child/myService'

@Component({
  selector: 'page-parent',
  templateUrl: 'parent.html',
})
export class ParentPage {
    i:number = 0;
    constructor(service:myService) {
        setInterval(()=> {
            service.change.emit(++this.i);
        }, 1000)
    }
}

parent.html

<ion-header>
  <ion-navbar>
    <ion-title>Parent</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
   <h1>parent {{i}}</h1>
   <page-child></page-child>
</ion-content>

child.ts

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

import{myService}from "../child/myService"
@Component({
  selector: 'page-child',
  templateUrl: 'child.html',
})
export class ChildPage {

    i:number = 0;

    constructor(public service:myService){
        service.change.subscribe((value:number)=>{
            this.i = value;
        })
    }
    
}

child.html

<ion-content padding>
 <h2>child {{i}}</h2>
</ion-content>

image.png

###7.订阅

parent.ts

import { Component } from '@angular/core';
import{myService}from '../child/myService'

@Component({
  selector: 'page-parent',
  templateUrl: 'parent.html',
})
export class ParentPage {
    i:number=0;
    constructor(public service:myService) {
        setInterval(()=> {
             this.service.StatusMission(this.i++);
        }, 1000)
    }
}

parent.html

<ion-header>
  <ion-navbar>
    <ion-title>Parent</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
   <h1>parent</h1>
   <page-child></page-child>
</ion-content>

child.ts

import { Component, Injectable } from '@angular/core'
import { myService } from "../child/myService"
import { Subscription } from 'rxjs/Subscription';
@Component({
    selector: 'page-child',
    templateUrl: 'child.html',
})
export class ChildPage {
    i:number=0;
    subscription: Subscription;
    constructor(private Service: myService) {
        this.subscription = Service.Status$.subscribe(message => {
            this.i=message;
        });
    }

    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
}

child.html

<ion-content padding>
  <h2>child {{i}}</h2> 
</ion-content>

myService.ts

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

@Injectable()
export class myService {

    private Source=new Subject<any>();
    Status$=this.Source.asObservable();
    StatusMission(message: any) {
        this.Source.next(message);
    }
}

image.png

本篇借鉴相关图片及部分代码,侵权即删

=======================分割线=======================

补充 - 子组件向父组件传值思路, - 核心:@Input - 思路:通过@Input在子组件中引用父组件的fn,并将子组件的值作为参数传入父组件方法,当子组件调用父组件时自然获取到了子组件的值。(思考弊端:父组件直接调用该方法时理论上会报错,同时子组件杂糅过多业务层逻辑,依赖父组件方法增加耦合,都是一定弊病)