angular 组件通信的几种实现方式


Posted in Javascript onJuly 13, 2018

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

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;
  });
 }
}

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

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

Javascript 相关文章推荐
Js与Jq获取浏览器和对象值的方法
Mar 18 Javascript
使用bat打开多个cmd窗口执行gulp、node
Feb 17 Javascript
详解使用JS如何制作简单的ASCII图与单极图
Mar 31 Javascript
AngularJs定时器$interval 和 $timeout详解
May 25 Javascript
jQuery 控制文本框自动缩小字体填充
Jun 16 jQuery
JavaScript之生成器_动力节点Java学院整理
Jun 30 Javascript
ionic3 懒加载
Aug 16 Javascript
深入理解JavaScript 中的匿名函数((function() {})();)与变量的作用域
Aug 28 Javascript
微信小程序 弹窗输入组件的实现解析
Aug 12 Javascript
Vue中多元素过渡特效的解决方案
Feb 05 Javascript
在vue中使用echarts(折线图的demo,markline用法)
Jul 20 Javascript
element中table高度自适应的实现
Oct 21 Javascript
JavaScript实现异步图像上传功能
Jul 12 #Javascript
Angular4 组件通讯方法大全(推荐)
Jul 12 #Javascript
vue移动端轻量级的轮播组件实现代码
Jul 12 #Javascript
详解node.js的http模块实例演示
Jul 12 #Javascript
Vue中使用的EventBus有生命周期
Jul 12 #Javascript
JavaScript中发出HTTP请求最常用的方法
Jul 12 #Javascript
vue实现引入本地json的方法分析
Jul 12 #Javascript
You might like
造就帕卡马拉的帕卡斯是怎么被发现的
2021/03/03 咖啡文化
PHP文件上传判断file是否己选择上传文件的方法
2014/11/10 PHP
swoole_process实现进程池的方法示例
2018/10/29 PHP
php7 参数、整形及字符串处理机制修改实例分析
2020/05/25 PHP
Jquery乱码的一次解决过程 图解教程
2010/02/20 Javascript
UserData用法总结 lanyu出品
2010/07/01 Javascript
jQuery.buildFragment使用方法及思路分析
2013/01/07 Javascript
js 控制下拉菜单刷新的方法
2013/03/03 Javascript
jquery实现固定顶部导航效果(仿蘑菇街)
2013/03/21 Javascript
jquery中.add()的使用分析
2013/04/26 Javascript
使用javascript创建快捷方式的简单实例
2013/08/09 Javascript
js 数值转换为3位逗号分隔的示例代码
2014/02/19 Javascript
jquery模拟LCD 时钟的html文件源代码
2014/06/16 Javascript
jquery获取checkbox的值并post提交
2015/01/14 Javascript
Jquery树插件zTree用法入门教程
2015/02/17 Javascript
javascript跨域原因以及解决方案分享
2015/04/08 Javascript
JS动画效果打开、关闭层的实现方法
2015/05/09 Javascript
Google 地图API资料整理及详细介绍
2016/08/06 Javascript
jquery中each循环的简单回滚操作
2017/05/05 jQuery
Angular2入门教程之模块和组件详解
2017/05/28 Javascript
解决webpack无法通过IP地址访问localhost的问题
2018/02/22 Javascript
element中el-container容器与div布局区分详解
2020/05/13 Javascript
Python做简单的字符串匹配详解
2017/03/21 Python
Python实现的弹球小游戏示例
2017/08/01 Python
python好玩的项目—色情图片识别代码分享
2017/11/07 Python
python+unittest+requests实现接口自动化的方法
2018/11/29 Python
python 实现在shell窗口中编写print不向屏幕输出
2020/02/19 Python
Python3以GitHub为例来实现模拟登录和爬取的实例讲解
2020/07/30 Python
Python函数__new__及__init__作用及区别解析
2020/08/31 Python
介绍一下SQL Server里面的索引视图
2016/07/31 面试题
检查接待方案
2014/02/27 职场文书
国培计划培训感言
2014/03/11 职场文书
党支部换届选举方案
2014/05/08 职场文书
民主生活会整改措施(党员)
2014/09/18 职场文书
社区安置帮教工作总结2015
2015/05/20 职场文书
观看禁毒宣传片后的感想
2015/08/11 职场文书