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; }); } }
这样订阅者就能动态的跟着发布源变化
总结: 以上就是常用的的通信方式,各种场景可以采取不同的方法。希望对大家的学习有所帮助,也希望大家多多支持。
下一篇: 微信小程序实现全局搜索时搜索结果高亮