JS和Vue中发布订阅原理实现之[浅尝辄止]

以前看到发布订阅总以为它是固定的代码,以为是什么算法。最近再学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标签的时候会首先考虑事件总线

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值