05-vue源码学习-发布订阅模式

发布订阅模式

目标: 解耦, 让各个模块之间没有紧密的联系

现在的处理办法是 属性在更新的 时候 调用 mountComponent 方法.

问题: mountComponent 更新的是什么??? (现在) 全部的页面 -> 当前虚拟 DOM 对应的页面 DOM

在 Vue 中, 整个的更新是按照组件为单位进行 判断, 已节点为单位进行更新.

  • 如果代码中没有自定义组件, 那么在比较算法的时候, 我们会将全部的模板 对应的 虚拟 DOM 进行比较.
  • 如果代码中含有自定义组件, 那么在比较算法的时候, 就会判断更新的是哪一些组件中的属性, 只会判断更新数据的组件, 其他组件不会更新.

复杂的页面是有很多组件构成. 每一个属性要更新的都要调用 更新的方法?

目标, 如果修改了什么属性, 就尽可能只更新这些属性对应的页面 DOM

这样就一定不能将更新的代码写死.

例子: 预售可能一个东西没有现货, 告诉老板, 如果东西到了 就告诉我.

老板就是发布者
订阅什么东西作为中间媒介
我就是订阅者

使用代码的结构来描述:

  1. 老板提供一个 账簿( 数组 )
  2. 我可以根据需求订阅我的商品( 老板要记录下 谁 定了什么东西, 在数组中存储 某些东西 )
  3. 等待, 可以做其他的事情
  4. 当货品来到的时候, 老板就查看 账簿, 挨个的打电话 ( 遍历数组, 取出数组的元素来使用 )

实际上就是事件模型

  1. 有一个 event 对象
  2. on, off, emit 方法

实现事件模型, 思考怎么用?

  1. event 是一个全局对象
  2. event.on( ‘事件名’, 处理函数 ), 订阅事件
    1. 事件可以连续订阅
    2. 可以移除: event.off()
      1. 移除所有
      2. 移除某一个类型的事件
      3. 移除某一个类型的某一个处理函数
  3. 写别的代码
  4. event.emit( ‘事件名’, 参数 ), 先前注册的事件处理函数就会依次调用

原因:

  1. 描述发布订阅模式
  2. 后面会使用到事件

发布订阅模式 ( 形式不局限于函数, 形式可以是对象等 ) :

  1. 中间的全局的容器, 用来存储可以被触发的东西( 函数, 对象 )
  2. 需要一个方法, 可以往容器中传入东西 ( 函数, 对象 )
  3. 需要一个方法, 可以将容器中的东西取出来使用( 函数调用, 对象的方法调用 )

事件模型代码

<script>
        // 全局的 event 对象, 提供 on, off, emit 方法  
        var event = (function () {
            eventObjs = {}
            return {
                /** 注册事件, 可以连续注册, 可以注册多个事件 */
                on: function (type, handler) {
                    (eventObjs[type] || (eventObjs[type] = [])).push(handler)
                },
                /** 移除事件, 
                 * - 如果没有参数, 移除所有事件, 
                 * - 如果只带有 事件名 参数, 就移除这个事件名下的所有事件,
                 * - 如果带有 两个 参数, 那么就是表示移除某一个事件的具体处理函数
                 * */
                off: function (type, handler) {
                    if (arguments.length === 0) {
                        eventObjs = {}
                    } else if (arguments.length === 1) {
                        eventObjs[type] = 1
                    } else if (arguments.length === 2) {
                        let _events = eventObjs[type]
                        if (!_events) return
                        for (let i = _events.length; i >= 0; i--) {
                            if (_events[i] === handler) {
                                _events.splice(i, 1)
                            }
                        }
                    }
                },
                /** 
                 * 发射事件, 触发事件, 包装参数 传递给事件处理函数
                */
                emit: function (type) {
                    let args = Array.prototype.splice.call(arguments, 1)// 或 arguments 从 1 开始后的所有参数, 返回的是数组
                    let _events = eventObjs[type]
                    if (!_events) return
                    for (let i = 0; i < _events.length; i++) {
                        _events[i].apply(null, args)
                    }
                }
            }
        }())
    </script>
    <script>
        function f() { console.log(1) }
        function foo() { console.log(2) }


        // 注册事件
        event.on('click', () => console.log('第一个 click 事件')); // 无法移除
        event.on('click', () => console.log('第2个 click 事件'));
        event.on('click', () => console.log('第3个 click 事件'));
        event.on('click', () => console.log('第4个 click 事件'));
        event.on('click', () => console.log('第5个 click 事件'));

        console.log(1);
        console.log(1);
        console.log(1);
        console.log(1);
        console.log(1);
        console.log(1);


        function f() {
            event.emit('click');
        }

        // js 中 基本类型是比较值
        // 引用类型是 比较 地址
        // 引用类型与基本类型, 是将其转换为 基本类型再比较 , 如果是 === 严格等于是不转换比较
    </script>```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值