Observer

作者: 小米和豆豆 | 来源:发表于2021-01-20 20:11 被阅读0次

///仅供学习使用

Create Observer

comn.service.ts
import { Injectable } from '@angular/core';
@Injectable({
  providedIn: 'root'
})
export class ComnService {
  constructor() { }
  public storeObj={};
  set(key,value){
    this.storeObj[key]=value
  }
  get(key){
    return this.storeObj[key];
  }
}
app-get-value.ts
import { Observable } from 'rxjs';
let OBS: Observable<any> = new Observable(observer => {
      //公共方法里获取数据
      let params = this.comnService.get('data')
      if (params) {
        this.title = params.title
        console.log(params)
      }
      observer.next(params);
    })
//将obs对象存起来,其他地方消费
this.comnService.set('OBSR', OBS)
app-set-value.ts
 this.OBS = this.comnService.get('OBSR');
 this.comnService.set('data', {
    type: 'set-title',
    title: new_title
 });
//上面修改值后 调用subscribe 来通知发布者,在app-get-value.ts会自动监听到变化,来执行响应操作
this.OBS.subscribe((res) => { 
  console.log(res)
});



Event Observer

    import { fromEvent } from 'rxjs';
    import { map } from 'rxjs/operators';

    // 创建发出点击事件的 observable
    const source = fromEvent(document, 'click');
    // 映射成给定的事件时间戳
    const example = source.pipe(map(event => `Event time: ${event.timeStamp}`));
    // 输出 (示例中的数字以运行时为准): 'Event time: 7276.390000000001'
    const subscribe = example.subscribe(val => console.log(val));

监听页面

  import { Observable } from 'rxjs';
  import {HostListener} from '@angular/core';
 // 监听页面大小变化
    Observable.fromEvent(window, 'resize').subscribe((event) => {
      console.log('页面变化了');
      console.log(event);
    });
    // 监听页面刷新
    Observable.fromEvent(window, 'beforeunload').subscribe((event) => {
      console.log('页面刷新了');
      console.log(event);
    });

@HostListener('window:resize', ['$event'])
  onResize(event) {
    event.target.innerWidth; 
  }

观察者模式:定义了对象间一种一对多的依赖关系,当目标对象 Subject 的状态发生改变时,所有依赖它的对象 Observer 都会得到通知。
优点 :

  1. 目标者与观察者,功能耦合度降低,专注自身功能逻辑;
  2. 观察者被动接收更新,时间上解耦,实时接收目标者更新状态;

缺点 :

  1. 不能对事件通知进行细分管控,如 “筛选通知”,“指定主题事件通知” 。
  2. 观察者对象不能只接收自己需要的更新通知 , 目标对象会通知所有观察者;
// 目标者类
class Subject {
  constructor() {
    this.observers = [];  // 观察者列表
  }
  // 添加
  add(observer) {
    this.observers.push(observer);
  }
  // 删除
  remove(observer) {
    let idx = this.observers.findIndex(item => item === observer);
    idx > -1 && this.observers.splice(idx, 1);
  }
  // 通知
  notify() {
    for (let observer of this.observers) {
      observer.update();
    }
  }
}

// 观察者类
class Observer {
  constructor(name) {
    this.name = name;
  }
  // 目标对象更新时触发的回调
  update() {
    console.log(`目标者通知我更新了,我是:${this.name}`);
  }
}

// 实例化目标者
let subject = new Subject();

// 实例化两个观察者
let obs1 = new Observer('小王');
let obs2 = new Observer('小李');

// 向目标者添加观察者
subject.add(obs1);
subject.add(obs2);

// 目标者通知更新
subject.notify();  
// 输出:
// 目标者通知我更新了,我是小王
// 目标者通知我更新了,我是小李

发布订阅模式(Publisher && Subscriber):基于一个事件(主题)通道,希望接收通知的对象 Subscriber 通过自定义事件订阅主题,被激活事件的对象 Publisher 通过发布主题事件的方式通知各个订阅该主题的 Subscriber 对象。

// 事件中心
let pubSub = {
  list: {},
  subscribe: function (key, fn) {   // 订阅
    if (!this.list[key]) {
      this.list[key] = [];
    }
    this.list[key].push(fn);
  },
  publish: function(key, ...arg) {  // 发布
    for(let fn of this.list[key]) {
      fn.call(this, ...arg);
    }
  },
  unSubscribe: function (key, fn) {     // 取消订阅
    let fnList = this.list[key];
    if (!fnList) return false;

    if (!fn) {
      // 不传入指定取消的订阅方法,则清空所有key下的订阅
      fnList && (fnList.length = 0);
    } else {
      fnList.forEach((item, index) => {
        if (item === fn) {
          fnList.splice(index, 1);
        }
      })
    }
  }
}

// 订阅
pubSub.subscribe('onwork', time => {
  console.log(`上班了:${time}`);
})
pubSub.subscribe('offwork', time => {
  console.log(`下班了:${time}`);
})
pubSub.subscribe('launch', time => {
  console.log(`吃饭了:${time}`);
})

// 发布
pubSub.publish('offwork', '18:00:00'); 
pubSub.publish('launch', '12:00:00');

// 取消订阅
pubSub.unSubscribe('onwork');

类似例子 DOM事件监听 vue 父子传值 pubsub.js 事件总线等

相关文章

网友评论

      本文标题:Observer

      本文链接:https://www.haomeiwen.com/subject/nuatwktx.html