热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Angular2ComponentsCommunicate

本文介绍的内容是组件通信的常用方式:@Input、@Output、@ViewChild、模板变量、MessageService、Broadcaster(Angular1.x$roo

本文介绍的内容是组件通信的常用方式:@Input、@Output、@ViewChild、模板变量、MessageService、Broadcaster (Angular 1.x $rootScope 中 $on、$broadcast ) 和 Pub – Sub 模式、RxJS Subject 存在的问题。

输入属性 (父组件 -> 子组件)

counter.component.ts

import { Component, Input } from '@angular/core';
@Component({
selector: 'exe-counter',
template: `

当前值: {{ count }}




`
})
export class CounterComponent {
@Input() count: number = 0;
increment() {
this.count++;
}
decrement() {
this.count--;
}
}

app.component.ts

import { Component } from '@angular/core';
@Component({
selector: 'exe-app',
template: `

`
})
export class AppComponent {
initialCount: number = 5;
}

输出属性 (子组件 -> 父组件)

counter.component.ts

import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'exe-counter',
template: `

当前值: {{ count }}




`
})
export class CounterComponent {
@Input() count: number = 0;
@Output() change: EventEmitter = new EventEmitter();
increment() {
this.count++;
this.change.emit(this.count);
}
decrement() {
this.count--;
this.change.emit(this.count);
}
}

app.component.ts

import { Component } from '@angular/core';
@Component({
selector: 'exe-app',
template: `

{{changeMsg}}


(change)="countChange($event)">
`
})
export class AppComponent {
initialCount: number = 5;
changeMsg: string;
countChange(event: number) {
this.changeMsg = `子组件change事件已触发,当前值是: ${event}`;
}
}

模板变量

child.component.ts

import {Component} from '@angular/core';
@Component({
selector: 'child-component',
template: `I'm {{ name }}`
})
export class ChildComponent {
public name: string;
}

parent.component.ts

import {Component, OnInit} from '@angular/core';
import {ChildComponent} from './child-component.ts';
@Component({
selector: 'parent-component',
template: `


`
})
export class ParentComponent implements OnInit {
private childName: string;
constructor() { }
ngOnInit() {
this.childName = 'child-component';
}
}

@ViewChild 装饰器

child.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
selector: 'exe-child',
template: `

Child Component


`
})
export class ChildComponent {
name: string = '';
}

app.component.ts

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child.component';
@Component({
selector: 'my-app',
template: `

Welcome to Angular World



`,
})
export class AppComponent {
@ViewChild(ChildComponent)
childCmp: ChildComponent;
ngAfterViewInit() {
this.childCmp.name = 'child-component';
}
}

使用 MessageService – 基于 RxJS Subject

message.service.ts

import { Injectable } from '@angular/core';
import {Observable} from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class MessageService {
private subject = new Subject();
sendMessage(message: string) {
this.subject.next({ text: message });
}
clearMessage() {
this.subject.next();
}
getMessage(): Observable {
return this.subject.asObservable();
}
}

home.component.ts

import { Component } from '@angular/core';
import { MessageService } from './message.service';
@Component({
selector: 'exe-home',
template: `


Home




`
})
export class HomeComponent {
constructor(private messageService: MessageService) {} sendMessage(): void {
this.messageService.sendMessage('Message from Home Component to App Component!');
}
clearMessage(): void {
this.messageService.clearMessage();
}
}

app.component.ts

import { Component, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { MessageService } from './message.service';
@Component({
selector: 'my-app',
template: `


{{message.text}}



`
})
export class AppComponent implements OnDestroy {
message: any;
subscription: Subscription;
constructor(private messageService: MessageService) {
this.subscription = this.messageService
.getMessage().subscribe( message => {
this.message = message;
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}

使用 Broadcaster – 基于 RxJS Subject

实现 Angular 1.x 中的 $rootScope 对象中 $on$broadcast 的功能。

broadcaster.ts

import { Injectable } from '@angular/core';
import {Subject} from 'rxjs/Subject';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
interface BroadcastEvent {
key: any;
data?: any;
}
@Injectable()
export class Broadcaster {
private _eventBus: Subject;
constructor() {
this._eventBus = new Subject();
}
broadcast(key: any, data?: any) {
this._eventBus.next({key, data});
}
on(key: any): Observable {
return this._eventBus.asObservable()
.filter(event => event.key === key)
.map(event => event.data);
}
}

child.component.ts

import { Component } from '@angular/core';
@Component({
selector: 'child'
})
export class ChildComponent {
constructor(private broadcaster: Broadcaster) {}
registerStringBroadcast() {
this.broadcaster.on('MyEvent')
.subscribe(message => {
...
});
}
emitStringBroadcast() {
this.broadcaster.broadcast('MyEvent', 'some message');
}
}

本文主要是介绍组件通讯的思路,提供的都是相对简单的示例。如果想深入了解,请参考 – angular.cn – component-communication。

我有话说

1.在实际开发中,我们也经常使用 Pub (发布) – Sub (订阅模式) 来实现模块之间的消息通讯。接下来我们看一下 Pub – Sub 的核心点:

  • 至少包含 subscribe() 和 publish() 两个方法,subscribe() 用于实现消息订阅,publish() 方法用于发布消息。

  • 支持订阅不同的消息类型,且对于任何一种消息类型都可以添加多个观察者。内部实现一般使用 key-value 结构进行消息类型和观察者列表的存储。

  • 订阅观察者后,最好返回一个对象或函数对象,用于取消订阅。

具体示例如下(详细信息,请参考 – Pub/Sub Javascript Object):

var events = (function(){
var topics = {};
var hOP = topics.hasOwnProperty;
return {
subscribe: function(topic, listener) {
// 如果topic类型不存在,则创建
if(!hOP.call(topics, topic)) topics[topic] = [];
// 添加listener
var index = topics[topic].push(listener) -1;
// 返回对象用于移除listener
return {
remove: function() {
delete topics[topic][index];
}
};
},
publish: function(topic, info) {
if(!hOP.call(topics, topic)) return;
topics[topic].forEach(function(item) {
item(info != undefined ? info : {});
});
}
};
})();

使用示例:

var subscription = events.subscribe('/page/load', function(obj) {
// 事件处理
});
events.publish('/page/load', {
url: '/some/url/path'
});

2.RxJS Subject 在使用中存在一个问题,就是如果某个 observer (观察者) 在执行的时候出现异常,却没有进行异常处理,那么就会影响到其它的观察者。解决该问题,最简单的方式就是为所有的观察者添加异常处理。具体问题如下:

const source = Rx.Observable.interval(1000);
const subject = new Rx.Subject();
const example = subject.map(x => {
if (x === 1) {
throw new Error('oops');
}
return x;
});
subject.subscribe(x => console.log('A', x));
example.subscribe(x => console.log('B', x));
subject.subscribe(x => console.log('C', x));
source.subscribe(subject);

以上代码运行后,控制台的输出结果:

A 0
B 0
C 0
A 1
Rx.min.js:74 Uncaught Error: oops

解决方案:

const source = Rx.Observable.interval(1000);
const subject = new Rx.Subject();
const example = subject.map(x => {
if (x === 1) {
throw new Error('oops');
}
return x;
});
subject.subscribe(
x => console.log('A', x),
error => console.log('A Error:' + error)
);example.subscribe(
x => console.log('B', x),
error => console.log('B Error:' + error)
);
subject.subscribe(
x => console.log('C', x),
error => console.log('C Error:' + error)
);
source.subscribe(subject);

关于 RxJS Subject 的详细信息,请查看 – RxJS Subject。


推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文详细介绍了 GWT 中 PopupPanel 类的 onKeyDownPreview 方法,提供了多个代码示例及应用场景,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 本文详细介绍如何使用arm-eabi-gdb调试Android平台上的C/C++程序。通过具体步骤和实用技巧,帮助开发者更高效地进行调试工作。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 本文详细介绍了如何使用 Yii2 的 GridView 组件在列表页面实现数据的直接编辑功能。通过具体的代码示例和步骤,帮助开发者快速掌握这一实用技巧。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • 作为一名新手,您可能会在初次尝试使用Eclipse进行Struts开发时遇到一些挑战。本文将为您提供详细的指导和解决方案,帮助您克服常见的配置和操作难题。 ... [详细]
  • 在使用 DataGridView 时,如果在当前单元格中输入内容但光标未移开,点击保存按钮后,输入的内容可能无法保存。只有当光标离开单元格后,才能成功保存数据。本文将探讨如何通过调用 DataGridView 的内置方法解决此问题。 ... [详细]
author-avatar
少少_LV
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有