手写发布订阅模式实现数据响应

教程来源于黑马的柴柴老师:https://cp_fe.gitee.io/course-advance/#/
现在还没时间完善步骤,先把代码贴上

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>手写发布订阅</title>
</head>
<body>
    <div id="app">
        <p v-text="name"></p>
        <p v-text="age"></p>
        <p v-text="name"></p>
    </div>
    <script>
        let data = {
            name: '区泽熙',
            age: 22,
            height: 176
        }
        // 遍历每一个属性
        Object.keys(data).forEach((key)=>{
            // key 属性名
            // data[key] 属性值
            // data 源对象
            defineReactive(data,key,data[key])
        })
        function defineReactive(data,key,value){
            Object.defineProperty(data,key,{
                get(){
                    return value
                },
                set(newValue){
                    // 数据发生变化,操作dom进行更新
                    if(newValue === value) return
                    value = newValue
                    // 再次编译要放到新值已经变化之后只更新当前的key
                    dep.trigger(key)   
                    console.log(dep)
                }
            })
        }
        // 增加dep对象,用来收集依赖和触发依赖
        const dep = {
            map: Object.create(null),
            // 收集
            collect(dataProp, updateFn){
                if(!this.map[dataProp]) this.map[dataProp] = []
                this.map[dataProp].push(updateFn)
            },
            // 触发
            trigger(dataProp){
                this.map[dataProp] && this.map[dataProp].forEach(updateFn => updateFn())
            }
        }
        // 编译函数
        function compile(){
            let app = document.getElementById('app')
            // 拿到app下所有的子元素
            const nodes = app.childNodes // [text, p, text, p, text, p, text]
            // 遍历所有的子元素
            nodes.forEach(node => {
                // nodeType为1是元素节点,3是文本结点
                if(node.nodeType === 1){
                    const attrs = node.attributes
                    // 遍历所有的attributes找到 v-text
                    Array.from(attrs).forEach(attr => {
                        const dirName = attr.nodeName
                        const dataProp = attr.nodeValue
                        console.log(dirName,dataProp)
                        if(dirName === 'v-text'){
                            console.log(`更新了${dirName}指令,需要更新的属性为${dataProp}`);
                            node.innerText = data[dataProp]
                            // 收集更新函数
                            dep.collect(dataProp,()=>{
                                node.innerText = data[dataProp]
                            })
                        }
                    })
                }
            })
        }
        compile()
    </script>
</body>
</html>
发布订阅模式又称观察者模式,是一种常见的设计模式,它定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。下面是手写JavaScript发布订阅模式的一种实现方式: ```javascript function PubSub() { this.subscribers = {}; } PubSub.prototype.subscribe = function(event, callback) { if (!this.subscribers[event]) { this.subscribers[event] = []; } this.subscribers[event].push(callback); }; PubSub.prototype.unsubscribe = function(event, callback) { if (!this.subscribers[event]) { return; } var index = this.subscribers[event].indexOf(callback); if (index > -1) { this.subscribers[event].splice(index, 1); } }; PubSub.prototype.publish = function(event, data) { if (!this.subscribers[event]) { return; } this.subscribers[event].forEach(function(callback) { callback(data); }); }; ``` 使用方式如下: ```javascript var pubsub = new PubSub(); function callback1(data) { console.log('callback1:', data); } pubsub.subscribe('event1', callback1); function callback2(data) { console.log('callback2:', data); } pubsub.subscribe('event2', callback2); pubsub.publish('event1', { message: 'hello' }); pubsub.publish('event2', { message: 'world' }); pubsub.unsubscribe('event1', callback1); pubsub.publish('event1', { message: 'hello again' }); ``` 输出结果为: ``` callback1: {message: "hello"} callback2: {message: "world"} ``` 当调用 `publish` 方法时,订阅了该事件的所有回调函数都将被执行,并且可以传递一个数据对象作为参数。调用 `subscribe` 方法注册一个回调函数,当该事件被发布时,该回调函数将被执行。调用 `unsubscribe` 方法取消订阅。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值