观察者模式的一种运用
场景
如上图,在一个歌曲详情模块,假设有2个子模块,歌曲模块和评论模块。 在歌曲模块和评论模块中都有评论数量这个属性,当用户在评论模块发布了一条评论后,评论模块和歌曲模块的数量要同步更新。 评论模块的数量很好更新,歌曲模块的评论数量怎么同步更新呢? 下面介绍几种实现方法。 思路:
在AppComponent将评论数量count作为输入参数(@Input)传递给CommentComponent和MusicComponent,当AppComponent中的评论数量改变时,MucisComponent中的评论数量也会同时改变。 AppComponent import { Component } from '@angular/core'; @Component({ selector: 'app-root',template: `<div> <app-music [count]="count"></app-music> <app-comment [(count)]="count"></app-comment> </div>` }) export class AppComponent { count:number = 0; constructor() { } } MusicComponent import { Component,Input } from '@angular/core'; @Component({ selector: 'app-music',template: `<div> <h3>歌曲模块</h3> <div>评论数:<strong>{{ count }}</strong></div> </div>`,styleUrls: ['./music.component.css'] }) export class MusicComponent{ // 评论数 @Input() count:number; constructor() { } } CommentComponent import { Component,EventEmitter,Input,Output } from '@angular/core'; @Component({ selector: 'app-comment',template: `<div> <h3>评论</h3> <div>评论数:<strong>{{ count }}</strong></div> <div> <textarea #content></textarea> </div> <div> <button (click)="send(content)">发布</button> </div> <ul> <li *ngFor="let item of comments"> {{ item }} </li> </ul> </div>` }) export class CommentComponent { // 评论数 @Input() count:number = 0; // 评论数改变事件 @Output() countChange:EventEmitter<number> = new EventEmitter<number>(); // 评论列表 comments:string [] = []; constructor() { } // 发送评论 send(content) { if (content.value) { this.comments.push(content.value); this.count++; this.countChange.emit(this.count); } } } 2. 观察者模式实现 思路
构建一个观察者对象,观察者对象拥有注册(regist),发布(fire),移除(remove)三个方法。在angular2中可以通过依赖注入注入到CommentComponent和MusicComponent。 在MusicComponent中注册(regist),‘count’ 事件。 当用户发送评论时,在CommentComponent中发布(fire),‘count’事件。 构造观察者对象 import { Injectable } from '@angular/core'; @Injectable() export class ObserverService { /** * 消息队列 * 用数组保存每一种消息的事件队列, * eventList['count'] = [] * 注册消息时将事件回调函数push到事件队列 * eventList['count'].push(fn) * 发布消息时依次执行消息队列中的每一个回调函数 * for(let fn of eventList['count']) { * fn(data); * } */ eventList = {}; constructor() { } /** * 发布消息 * @param name 消息名 * @param data 消息数据 */ fire(name:string,data:any) { if (this.eventList[name]) { const fns = this.eventList[name]; for(let fn of fns) { fn(data); } } } /** * 注册消息 * @param name * @param fn */ regist(name:string,fn:any) { if (typeof fn === 'function') { const fns = this.eventList[name]; if (fns) { fns.push(fn); } else { this.eventList[name] = [fn]; } } } /** * 移除消息 * @param name * @param fn */ remove(name:string,fn:any) { const fns = this.eventList[name]; if (fns) { if ( fn ) { let i; for(i = 0; i < fns.length; i++) { if (fns[i] === fn) { break; } } if (i < fns.length) { fns.splice(i,1); } } else { fns.length = 0; } } } } AppComponent import { Component } from '@angular/core'; @Component({ selector: 'app-root',template: `<div> <app-music></app-music> <app-comment></app-comment> </div>` }) export class AppComponent { constructor() { } } MusicComponent import { ObserverService } from '../service/observer.service'; import { Component,styleUrls: ['./music.component.css'] }) export class MusicComponent{ // 评论数 count:number; constructor(private observiceService:ObserverService) { // 注册消息 this.observiceService.regist('count',count => this.count = count); } } CommentComponent import { ObserverService } from '../service/observer.service.2'; import { Component,template: `<div> <h3>评论</h3> <div>评论数:<strong>{{ count }}</strong></div> <div> <textarea #content></textarea> </div> <div> <button (click)="send(content)">发布</button> </div> <ul> <li *ngFor="let item of comments"> {{ item }} </li> </ul> </div>` }) export class CommentComponent { // 评论数 count:number = 0; // 评论列表 comments:string [] = []; constructor(private observiceService:ObserverService) { } send(content) { if (content.value) { this.comments.push(content.value); this.count++; // 发布消息 this.observiceService.fire('count',this.count); } } } 3. 使用Rxjs中的Subject实现 subject参考 SubjectService import { Observable,Subject } from 'rxjs/Rx'; @Injectable() count:number = 0; comment:Subject<number>; constructor() { this.comment = new Subject<number>(); } } AppComponent import { Component } from '@angular/core'; @Component({ selector: 'app-root',template: `<div> <app-music></app-music> <app-comment></app-comment> </div>` }) export class AppComponent { constructor() { } } MusicComponent import { SubjectService } from '../service/subject.service'; import { Component,styleUrls: ['./music.component.css'] }) export class MusicComponent{ // 评论数 count:number; constructor(private subjectService:SubjectService) { // 注册消息 this.subjectService.comment.subscribe(count => this.count = count); } } 4. 小结
CommentComponent
MusicComponent
MusicComponent
CommentComponent
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |