单页面应用组件通信有以下几种,这篇文章主要讲 Angular 通信

  • 父组件 => 子组件
  • 子组件 => 父组件
  • 组件A = > 组件B

父组件 => 子组件 子组件 => 父组件 sibling => sibling
@input @output
setters (本质上还是@input) 注入父组件
ngOnChanges() (不推荐使用)
局部变量
@ViewChild()
service service service
Rxjs的Observalbe Rxjs的Observalbe Rxjs的Observalbe
localStorage,sessionStorage localStorage,sessionStorage localStorage,sessionStorage

上面图表总结了能用到通信方案,期中最后3种,是通用的,angular的组件之间都可以使用这3种,其中Rxjs是最最牛逼的用法,甩redux,promise,这些同样基于函数式的状态管理几条街,下面一一说来

父组件 => 子组件

@input,最常用的一种方式

@Component({
 selector: 'app-parent',
template: '<div>childText:<app-child [textContent] = "varString"></app-child></div>',
 styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {
 varString: string;
 constructor() { }
 ngOnInit() {
  this.varString = '从父组件传过来的' ;
 }
}
import { Component, OnInit, Input } from '@angular/core';
@Component({
 selector: 'app-child',
 template: '<h1>{{textContent}}</h1>',
 styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
 @Input() public textContent: string ;
 constructor() { }
 ngOnInit() {
 }
}

setter

setter 是拦截@input 属性,因为我们在组件通信的时候,常常需要对输入的属性处理下,就需要setter了,setter和getter常配套使用,稍微修改下上面的child.component.ts

child.component.ts

import { Component, OnInit, Input } from '@angular/core';
@Component({
 selector: 'app-child',
 template: '<h1>{{textContent}}</h1>',
 styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
_textContent:string;
 @Input()
 set textContent(text: string){
  this._textContent = !text: "啥都没有给我" ? text ;
 } ;
 get textContent(){
 return this._textContent;
 }
 constructor() { }
 ngOnInit() {
 }
}

onChange

这个是通过angular生命周期钩子来检测,不推荐使用,要使用的话可以参angular文档

@ViewChild()

@ViewChild() 一般用在调用子组件非私有的方法

      import {Component, OnInit, ViewChild} from '@angular/core';
    import {ViewChildChildComponent} from "../view-child-child/view-child-child.component";
  @Component({
   selector: 'app-parent',
   templateUrl: './parent.component.html',
   styleUrls: ['./parent.component.css']
  })
  export class ParentComponent implements OnInit {
   varString: string;
   @ViewChild(ViewChildChildComponent)
   viewChildChildComponent: ViewChildChildComponent;
   constructor() { }
   ngOnInit() {
    this.varString = '从父组件传过来的' ;
   }
   clickEvent(clickEvent: any) {
    console.log(clickEvent);
    this.viewChildChildComponent.myName(clickEvent.value);
   }
  }
   import { Component, OnInit } from '@angular/core';
  @Component({
   selector: 'app-view-child-child',
   templateUrl: './view-child-child.component.html',
   styleUrls: ['./view-child-child.component.css']
  })
  export class ViewChildChildComponent implements OnInit {
   constructor() { }
   name: string;
   myName(name: string) {
     console.log(name);
     this.name = name ;
   }
   ngOnInit() {
   }
  }

局部变量

局部变量和viewChild类似,只能用在html模板里,修改parent.component.html,通过#viewChild这个变量来表示子组件,就能调用子组件的方法了.

<div class="panel-body">
  <input class="form-control" type="text" #viewChildInputName >
  <button class=" btn btn-primary" (click)="viewChild.myName(viewChildInputName.value)">局部变量传值</button>
  <app-view-child-child #viewChild></app-view-child-child>
      </div>

child 组件如下

@Component({
 selector: 'app-view-child-child',
 templateUrl: './view-child-child.component.html',
 styleUrls: ['./view-child-child.component.css']
})
export class ViewChildChildComponent implements OnInit {

 constructor() { }
 name: string;
 myName(name: string) {
   console.log(name);
   this.name = name ;
 }
 ngOnInit() {
 }

}

子组件 => 父组件

@output()

output这种常见的通信,本质是给子组件传入一个function,在子组件里执行完某些方法后,再执行传入的这个回调function,将值传给父组件

parent.component.ts

@Component({
 selector: 'app-child-to-parent',
 templateUrl: './parent.component.html',
 styleUrls: ['./parent.component.css']
})
export class ChildToParentComponent implements OnInit {

 childName: string;
 childNameForInject: string;
 constructor( ) { }
 ngOnInit() {
 }
 showChildName(name: string) {
  this.childName = name;
 }
}

parent.component.html

<div class="panel-body">
 <p>output方式 childText:{{childName}}</p>
 <br>
 <app-output-child (childNameEventEmitter)="showChildName($event)"></app-output-child>
</div>
 child.component.ts
 export class OutputChildComponent implements OnInit {
 // 传入的回调事件
 @Output() public childNameEventEmitter: EventEmitter<any> = new EventEmitter();
 constructor() { }
 ngOnInit() {
 }
 showMyName(value) {
  //这里就执行,父组件传入的函数
  this.childNameEventEmitter.emit(value);
 }
}

注入父组件

这个原理的原因是父,子组件本质生命周期是一样的

export class OutputChildComponent implements OnInit {
 // 注入父组件
 constructor(private childToParentComponent: ChildToParentComponent) { }
 ngOnInit() {
 }
 showMyName(value) {
  this.childToParentComponent.childNameForInject = value;
 }
}

sibling组件 => sibling组件

service

Rxjs

通过service通信

angular中service是单例的,所以三种通信类型都可以通过service,很多前端对单例理解的不是很清楚,本质就是
,你在某个module中注入service,所有这个modul的component都可以拿到这个service的属性,方法,是共享的,所以常在app.moudule.ts注入日志service,http拦截service,在子module注入的service,只能这个子module能共享,在component注入的service,就只能子的component的能拿到service,下面以注入到app.module.ts,的service来演示

user.service.ts

@Injectable()
export class UserService {
 age: number;
 userName: string;
 constructor() { }
}

app.module.ts

@NgModule({
 declarations: [
  AppComponent,
  SiblingAComponent,
  SiblingBComponent
 ],
 imports: [
  BrowserModule
 ],
 providers: [UserService],
 bootstrap: [AppComponent]
})
export class AppModule { }
SiblingBComponent.ts
@Component({
 selector: 'app-sibling-b',
 templateUrl: './sibling-b.component.html',
 styleUrls: ['./sibling-b.component.css']
})
export class SiblingBComponent implements OnInit {
 constructor(private userService: UserService) {
  this.userService.userName = "王二";
 }
 ngOnInit() {
 }
}

SiblingAComponent.ts

@Component({
 selector: 'app-sibling-a',
 templateUrl: './sibling-a.component.html',
 styleUrls: ['./sibling-a.component.css']
})
export class SiblingAComponent implements OnInit {
 userName: string;
 constructor(private userService: UserService) {
 }
 ngOnInit() {
  this.userName = this.userService.userName;
 }
}

通过Rx.js通信

这个是最牛逼的,基于订阅发布的这种流文件处理,一旦订阅,发布的源头发生改变,订阅者就能拿到这个变化;这样说不是很好理解,简单解释就是,b.js,c.js,d.js订阅了a.js里某个值变化,b.js,c.js,d.js立马获取到这个变化的,但是a.js并没有主动调用b.js,c.js,d.js这些里面的方法,举个简单的例子,每个页面在处理ajax请求的时候,都有一弹出的提示信息,一般我会在
组件的template中中放一个提示框的组件,这样很繁琐每个组件都要来一次,如果基于Rx.js,就可以在app.component.ts中放这个提示组件,然后app.component.ts订阅公共的service,就比较省事了,代码如下

首先搞一个alset.service.ts

import {Injectable} from "@angular/core";
import {Subject} from "rxjs/Subject";
@Injectable()
export class AlertService {
 private messageSu = new Subject<string>(); //
 messageObserve = this.messageSu.asObservable();
 private setMessage(message: string) {
  this.messageSu.next(message);
 }
 public success(message: string, callback?: Function) {
  this.setMessage(message);
  callback();
 }
}

sibling-a.component.ts

@Component({
 selector: 'app-sibling-a',
 templateUrl: './sibling-a.component.html',
 styleUrls: ['./sibling-a.component.css']
})
export class SiblingAComponent implements OnInit {
 userName: string;
 constructor(private userService: UserService, private alertService: AlertService) {
 }
 ngOnInit() {
  this.userName = this.userService.userName;
  // 改变alertService的信息源
  this.alertService.success("初始化成功");
 }
}

app.component.ts

@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrls: ['./app.component.css']
})
export class AppComponent {
 title = 'app';
 message: string;
 constructor(private alertService: AlertService) {
  //订阅alertServcie的message服务
   this.alertService.messageObserve.subscribe((res: any) => {
   this.message = res;
  });
 }
}

这样订阅者就能动态的跟着发布源变化

总结: 以上就是常用的的通信方式,各种场景可以采取不同的方法。希望对大家的学习有所帮助,也希望大家多多支持Devmax。

angular 组件通信的几种实现方式的更多相关文章

  1. 详解html5 postMessage解决跨域通信的问题

    这篇文章主要介绍了详解html5 postMessage解决跨域通信的问题的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. 详解使用postMessage解决iframe跨域通信问题

    这篇文章主要介绍了详解使用postMessage解决iframe跨域通信问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. HTML5调用手机发短信和打电话功能

    这篇文章主要介绍了HTML5调用手机发短信和打电话功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. 真正的iOS设备和Watch Simulator可以进行通信以进行测试

    我想为现有的iOS应用创建一个手表应用.但我处于一种情况,我没有苹果手表,我现有的iOS应用程序只能在不在模拟器上的真实设备上运行.是否可以在iPhone设备上运行应用程序并在手表模拟器中测试我的手表应用程序?解决方法至少在目前,不可能配对真正的iPhone和Watch模拟器.我得出这个结论有三个原因:>Watch模拟器在安装过程中自动与iPhone模拟器配对.>根本无法从界面取消配对Watch模拟器.>在模拟器上无法访问蓝牙以与真实设备进行通信.这是一个proof.

  5. ios – 如何使用iphone使用蓝牙或wifi与OBD II进行通信

    我想为iOS创建一个简单的应用程序,它通过ODBIIWifi/蓝牙设备从汽车读取数据并在iPhone屏幕上显示.但我不知道从哪里开始.请有人帮我实现以下结果.我有蓝牙和wifi加密狗.第1步:配对蓝牙或Wifi加密狗和iPhone.第2步:通过加密狗阅读详细信息请参阅我能够轻松理解的任何教程或示例代码.我想深入了解这些过程,并希望自己编写代码.所以请帮忙.提前致谢.解决方法正如David所说,在i

  6. ios – Arduino和iPhone与蓝牙3.0的连接

    我想构建一个需要蓝牙连接的应用程序.蓝牙HC05模块连接到Arduino.我想知道构建可连接到此蓝牙模块的应用程序所需的框架.仍然不知道如何开始.有人可以帮忙吗?

  7. 可以通过iOS中的蓝牙PAN与系留设备进行通信

    我有一个设备,我通过蓝牙从iOS设备分享我的连接.我想知道是否可以访问在PAN网络上的iPhone上创建服务器并从设备访问它或在设备上创建服务器并从iPhone访问它.有没有人有这种经历?

  8. ios – 与容器视图通信的最佳实践是什么?

    我最近经常使用容器VC,我一直想知道主Vc和容器VC之间的最佳通信方式是什么.现在我正在使用通知,但我宁愿使用更好的东西.如何获取指向容器VC的指针,以便至少可以使用委托?

  9. ios – ViewModel和Controller之间通信的最佳方式

    我是开发新手,最近练习MVVM设计模式.在viewmodel&控制器我正在使用Closure.我知道我也可以使用Delegate.但是有什么惯例或理由我应该遵循什么样的沟通方式.我有点困惑.任何帮助将不胜感激.解决方法我也在寻找这个答案,我发现了这个,将UI层(UIL)中的闭包传递到业务逻辑层(BLL)会破坏关注点(SOC).您准备的数据驻留在BLL中,所以基本上您会说“嘿BLL为我执行此UIL逻

  10. swift 实现websocket与后台通信(swift 如何构建简单的json字符串)

    一个应用不可避免要与服务器进行通信,主要有,http与socket。http暂时不论,我们先看看socket下面衍生的websocket,今天我就把自己怎么利用websocket与服务器进行交互记录下来:首先你需要集成websocket到自己的项目,如果不明白如何集成,请看上一篇《swift集成websocket库》集成websocket到自己项目后还需要添加SwiftyJSON到自己项目,具体步骤和集成websocket一样。首先打开你项目,记得通过cocoapods生成的.xcworkspace文件打

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部