一、发布订阅

1.目的

    解耦,让各个组件之间没有紧密的联系,如果修改了什么属性,就尽可能更新这些属性对应的页面DOM

2.步骤描述

      1)需要有中间的全局容器=》一个数组存放所有的订阅(watcher),发布的时候在这个里面取可以被触发的东西(函数、对称)
      2)可以根据需求来订阅东西
      3)等等,可以做一些其他的事情
      4)当有某些需求就去查看全局容器,取出相应的东西来用

3.代码描述

     1.eventObj={}描述存储的容器
      2.event.on('事件名',响应函数)
          1)订阅事件 可以连续订阅
          2)可以移除:event.off()
              移除所有
              移除某一个类型的事件
              移除某一类事件的某一个处理函数
      3.处理别的代码
      4.event.emit('事件名',参数),先前注册的时间处理函数会依次调用

二、Vue中的更新规则及模型

1.更新规则

 在Vue中整个更新是按照**组件**为单位进行判断的,以节点为单位进行更新:
 1)如果没有自定义组件,在比较算法的时候会将全部模板对应的虚拟DOM进行比较
 2)如果有自定义组件,在比较算法的时候会判断更新的是哪一些组件中的属性,只会判断更新数据的组件,其他组件不会更新

2.模型


3.为什么设计为多个watcher?

    每个组件都会对应一个watcher,初始渲染的时候会将所有的watcher都加入全局容器中,而往往开发中只有一部分组件的数据会发生变化,diff算法也只会对这部分组件重新生成抽象语法树,也只会访问这部分watcher,将这部分watcher再次被添加入全局的watcher中,其他的就不在了,因此页面更新的时候只会更新这一部分而不是全部更新,会提升一些渲染效率

三、实现

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    var event = (function () {
      eventObj = {};
      return {
        /** 注册事件,可以连续注册并且能注册多个事件*/
        on: function (type, handler) {
          (eventObj[type] || (eventObj[type] = [])).push(handler);
        },

        /** 移除事件
         * 如果没有参数就移除全部事件
         * 如果有一个参数,就移除这个事件名下的所有事件
         * 如果有两个参数,就移除这个事件中的这个具体的处理函数*/
        off: function (type, handler) {
          if (arguments.length === 0) {
            eventObj = {};
          } else if (arguments.length === 1) {
            eventObj[type] = [];
          } else if (arguments.length === 2) {
            if (!eventObj[type]) return;/** 如果没有这个事件名,则直接返回*/
            for (let i = eventObj[type].length - 1; i >= 0; i--) {
              if (eventObj[type][i] == handler) {
                eventObj[type].splice(i, 1);
              }

            }
          }
        },

        /** 发射事件(触发事件)
         * 包装参数,传递给时间处理函数
        */
        emit: function (type) {
          if (!eventObj[type]) return;
          let args = Array.prototype.slice.call(arguments, 1);
          for (let i = 0; i < eventObj[type].length - 1; i++) {
            eventObj[type][i].call(null, args);
          }
        }
      }
    })
  </script>
</body>

</html>