Angular2官方文档对组件交互这块有详细的介绍-->文档--组件之间的交互。按文档介绍,组件间交互的方式一共有4种,包括:
- 通过输入型绑定把数据从父组件传到子组件(@Input decoration);子组件暴露一个EventEmitter属性(@Output decoration),当事件发生时,利用该属性emits向父组件发射事件。
- 父组件与子组件通过本地变量互动。(# var)
- 父组件调用@ViewChild。
- 父组件和子组件通过服务来通讯。
我在这里只总结、详细介绍3种我在项目中使用过的方法,看完本文大概能做到如下的效果:
创建项目,项目结构如下:
通过@Input、@Output装饰器进行父、子组件间的通信
@Input:该属性绑定用于父组件向子组件传递数据。子组件可以通过以下两种方法截取属性的变更:
- 使用一个输入属性的setter,以拦截父组件中值得变化。
- 通过ngOnchanges()来截听输入属性值的变化。
@Output:该数据绑定用于子组件向父组件传递数据和事件。
<!--parent.component.html--> <div style="width: 1000px;margin: auto"> <div class="card" style="width: 500px;float: left"> <div class="card-header"> 父组件 </div> <div class="card-body"> <h5 class="card-title">父组件</h5> <div class="form-group"> <label for="input">父组件输入:</label> <input type="text" class="form-control" id="input" placeholder="Input something" [(ngModel)]="parentPrint" > <label for="output">父组件输出:</label> <input type="text" class="form-control" id="output" placeholder="Output something" [(ngModel)]="contentFromChild" > </div> </div> </div> <app-child [fromParent]="parentPrint" (fromChild)="fromChild($event)" ></app-child> </div>
<!--child.component.html--> <div class="card" style="width: 500px;"> <div class="card-header"> 子组件 </div> <div class="card-body"> <h5 class="card-title">子组件</h5> <div class="form-group"> <label for="input">子组件输入:</label> <input type="text" class="form-control" id="input" placeholder="Input something" [(ngModel)]="contentFromChild" > <label for="output">子组件输出:</label> <input type="text" class="form-control" id="output" placeholder="Output something" [(ngModel)]="fromParent" > </div> <button class="btn btn-primary" (click)="clickChild()">Output方式</button> </div> </div>
效果如下:(1、父组件输入,子组件可同步输出;2、子组件输入需要(3、)点击按钮触发发射事件,将数据传送给父组件。)
@Input:父组件输入的同时,子组件能同步获取数据进行显示。核心代码如下:
//父组件 parentPrint: any; //ts中,声明一个变量 [(ngModel)]="parentPrint" //html中,绑定变量,获取用户输入 //html中,将数据传给子组件 <app-child [fromParent]="parentPrint"></app-child> //子组件 @Input() fromParent; //ts中,用于直接接收从父组件获取的数据 [(ngModel)]="fromParent" //html中,用于显示数据
通过setter截听输入属性值的变化,在子组件中声明一个私有变量来获取父组件传递过来的数据,从而屏蔽上层获取下层信息。(简单一点就是不让父组件知道子组件用什么东西去接收传过来的数据)通过这种方法也可以获得同样的效果。
//子组件 private _fromParent: any; //私有变量,通过setter获取父组件的数据 @Input() //通过setter获取父组件的数据 set fromParent(fromParent: any) { this._fromParent = fromParent; } get fromParent(): any { return this._fromParent; }
@Output:父组件接收子组件的数据时,子组件暴露一个EventEmitter属性,当事件发生时,子组件利用该属性emits(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。核心代码如下:
//子组件 @Output() fromChild = new EventEmitter<any>(); //暴露一个输出属性 <button class="btn btn-primary" (click)="clickChild()">Output方式</button> //触发发射函数,将数据发送给父组件 clickChild() { console.log('click child' , this.contentFromChild); this.fromChild.emit(this.contentFromChild); }
//父组件 [(ngModel)]="contentFromChild" //绑定输出子组件的数据 //使用子组件,绑定事件属性 <app-child [fromParent]="parentPrint" (fromChild)="fromChild($event)" ></app-child> //事件处理函数 fromChild(event) { console.log(event); this.contentFromChild = event; }
父组件通过调用@ViewChild()来获取子组件的数据
如果父组件的类需要读取子组件的属性和值或调用子组件的方法时,就可以把子组件作为ViewChild,注入到父组件里面。ViewChild顾名思义就是可以看见子组件里面的属性和方法。
<!--parent.component.html--> <div style="width: 1000px;margin: auto"> <div class="card" style="width: 500px;float: left"> <div class="card-header"> 父组件 </div> <div class="card-body"> <h5 class="card-title">父组件</h5> <div class="form-group"> <label for="viewoutput">ViewChild父组件输出:</label> <input type="text" class="form-control" id="viewoutput" placeholder="ViewChild父组件输出" [(ngModel)]="viewOutput" > </div> <button class="btn btn-primary" (click)="clickView()">ViewChild方式</button> </div> </div> <app-child></app-child> </div>
<!--child.component.html--> <div class="card" style="width: 500px;"> <div class="card-header"> 子组件 </div> <div class="card-body"> <h5 class="card-title">子组件</h5> <div class="form-group"> <label for="input">子组件输入:</label> <input type="text" class="form-control" id="input" placeholder="Input something" [(ngModel)]="contentFromChild" > </div> </div> </div>
效果如下:
父组件核心代码:
//ts @ViewChild(ChildComponent) // 使用viewChild导入引用 private childComponent: ChildComponent; // 将子组件注入到私有属性 //获取子组件数据并显示 clickView() { //直接获取子组件的属性 this.viewOutput = this.childComponent.contentFromChild; }
//html [(ngModel)]="viewOutput" <button class="btn btn-primary" (click)="clickView()">ViewChild方式</button>
父组件和子组件通过服务来通讯
父组件和它的子组件共享同一个服务,利用该服务在家庭内部实现双向通讯。
<!--parent.component.html--> <div style="width: 1000px;margin: auto"> <div class="card" style="width: 500px;float: left"> <div class="card-header"> 父组件 </div> <div class="card-body"> <h5 class="card-title">父组件</h5> <div class="form-group"> <label for="serviceoutput">父组件服务输入:</label> <input type="text" class="form-control" id="serviceoutput" placeholder="服务输入" [(ngModel)]="serviceInput" > </div> <button class="btn btn-primary" (click)="clickService()">Service方式</button> </div> </div> <app-child></app-child> </div>
<!--child.component.html--> <div class="card" style="width: 500px;"> <div class="card-header"> 子组件 </div> <div class="card-body"> <h5 class="card-title">子组件</h5> <div class="form-group"> <label for="serviceoutput">子组件服务输入:</label> <input type="text" class="form-control" id="serviceoutput" placeholder="服务输入" [(ngModel)]="serviceInput" > </div> <button class="btn btn-primary" (click)="clickService()">Service方式</button> </div> </div>
//服务 //meditor.service.ts import {Injectable} from '@angular/core'; import {Subject} from 'rxjs/Subject'; import {Observable} from 'rxjs/Observable'; @Injectable() export class MeditorService { private subject = new Subject<MeditorMsg>(); constructor() {} // 获取订阅者 public getObservable(): Observable<MeditorMsg> { return this.subject.asObservable(); } // 推送信息 public push(msg: MeditorMsg) { this.subject.next(msg); } } // 中间者信息 export interface MeditorMsg { id: string; body: any; }
效果如下:
父子组件的核心代码类似,在构造函数中将该服务实例注入到自身,父子组件都有一个唯一的id。无论是父组件还是子组件调用push()方法推送数据,双方都能接收到数据,这时候就要根据id来判断是要父组件使用数据还是子组件使用数据。核心代码如下:
subscription: Subscription = null; //初始化一个订阅对象 //子组件构造函数,用于监听数据推送 constructor( private meditor: MeditorService ) { this.subscription = meditor.getObservable().subscribe( msg => { console.log(msg); if (msg.id === 'parent') { //id为parent,获取父组件数据 this.serviceInput = msg.body; } } ); } // 子组件将数据推送到中间着,给订阅者 clickService() { this.meditor.push({id: 'parent', body: this.serviceInput}); } //父组件构造函数,用于监听数据推送 constructor( private meditor: MeditorService ) { this.subscription = meditor.getObservable().subscribe( msg => { console.log(msg); if (msg.id === 'child') { //id为child,获取子组件数据 this.serviceInput = msg.body; } } ); } // 父组件将数据推送到中间着,给订阅者 clickService() { this.meditor.push({id: 'parent', body: this.serviceInput}); }
我上面写的还不是很完善,就是在生命周期结束前,也就是在onDestroy周期中,要取消订阅。
以上,就是最近在使用的组件交互的总结。个人觉得通过服务来交互的可扩展性更强。例如,我们项目中用到了一个动态显示的侧栏,不同时期点击显示侧栏要显示不同的东西。这个时候把侧栏作为父组件,子组件作为消息的一部分传递给父组件,父组件根据子组件名动态生成模板,显示在侧栏上面。说了这么多废话大概就是下图的意思:
最后附上demo源码:父子组件交互demo
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]