以前看到发布订阅总以为它是固定的代码,以为是什么算法。最近再学Vue的响应式原理,顺便了解一下这个。才发现它只是一种设计思想,记录一下,以备run。
1. 封装PubSub类
PubSub.js
class PubSub {
constructor() {
this.subs = {
}; // 存储自定义事件
}
subscribe(type, fn) {
//订阅 type是任务队列的类型 ,fn是方法
if (!this.subs[type]) {
// 判断在 subs是否有当前类型的 方法队列存在
this.subs[type] = []; // 没有就新增一个 默认为空数组
}
this.subs[type].push(fn); // 把方法加到该类型中
}
isFunction(fn) {
return fn && Object.prototype.toString.call(fn).includes('Function');
}
publish(type) {
// 发布
let fns = this.subs[type];
if (fns && Array.isArray(fns)) {
const args = Array.prototype.slice.call(arguments, 1); // 获取到参数
fns.forEach(fn=> fn(...args)); // 循环队列调用 fn
}
}
unsubscribe(type, fn) {
// 取消订阅
const currentEvents = this.subs[type];
if (currentEvents) {
const resObj = {
};
Object.keys(this.subs).forEach(eachSub=> {
if (eachSub !== type) {
resObj[eachSub] = this.subs[eachSub]
}
});
this.subs = resObj;
if (this.isFunction(fn)) {
fn();
}
}
}
}
export default PubSub;
2. 在Vue项目中验证
比如有父组件shopList和两个子组件Book.vue/Pay.vue
在入口文件如main.js
中引入并挂载pubSub
实例
main.js
import PubSub from "../../../../Mark/prepare/概念实现/08.发布订阅";
Vue.prototype.$pubsub = new PubSub();
shopList.vue
<div class="fill-contain">
商家
<book/>
<pay/>
</div>
Pay.vue
<template>
<div>
<h1>我是收银台,您本次购买的图书价格是: {
{
cost}}</h1>
<h1>现在的时间是:{
{
nowTime}}</h1>
<el-button @click="initPubSub" type="primary">手动订阅</el-button>
</div>
</template>
<script>
export default {
name: "Pay",
data() {
return {
cost: 0,
nowTime: '',
}
},
mounted(){
this.initPubSub();
},
methods: {
initPubSub() {
this.$pubsub.subscribe('sendPay', (data, time)=> {
this.cost = data;
this.nowTime = time;
});
}
}
}
</script>
<style scoped>
</style>
Book.vue
<template>
<div>
<h1>买书</h1>
<el-button type="primary" @click="handleSendPay">发送价格</el-button>
<el-button type="primary" @click="handleCancelSub">取消订阅</el-button>
</div>
</template>
<script>
export default {
name: "Book",
methods: {
handleSendPay() {
this.$pubsub.publish('sendPay', 300, new Date().toLocaleString())
},
handleCancelSub() {
this.$pubsub.unsubscribe('sendPay', (d)=> {
console.log('取消订阅sendPay成功---', d);
})
},
}
}
</script>
当前在Vue中有现成的基于发布订阅设计思想实现的比如事件总线
,一般我遇到动态组件即<component标签的时候会首先考虑事件总线