Vue双向数据绑定内部实现原理

Vue 采用 数据劫持 结合 发布者-订阅者 模式的方式,通过 Object.defineProperty() 来劫持各个属性的setter 以及 getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
步骤分为以下几步:

  • 第一步:需要 Observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 settergetter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。

  • 第二步:Compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新数据。

  • 第三步:Watcher 订阅者是 ObserverCompile 之间通信的桥梁,主要做的事情有:
    在自身实例化时往属性订阅器(dep)里面添加自己。
    自身必须有一个 update() 方法
    待属性变动 dep.notice() 通知时,能调用自身的 update() 方法,并触发Compile 中绑定的回调,则功成身退。

  • 第四步 :MVVM作为数据绑定的入口,整合Observer、CompileWatcher 三者,通过 Observer来监听自己的model数据变化,通过Compile 来解析编译模板指令,最终利用 Watcher 搭起 ObserverCompile之间的桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据 model 变更的双向绑定效果。

js实现简单的双向数据绑定

<body>
  <div id="app">
    <input type="text" id="txt">
    <p id="show"></p>
  </div>
  
  <script>
    window.onload = function() {
      let obj = {};
      Object.defineProperty(obj, "txt", {
        get: function() {
          return obj;
        },
        set: function(newValue) {
          document.getElementById("txt").value = newValue;
          document.getElementById("show").innerHTML  = newValue;
        }
      })
      document.addEventListener("keyup", function(e) {
        obj.txt = e.target.value;
      })
    }
  </script>
</body>

Object.defineProperty 接收三个参数:对象,属性名,配置对象
这里使用的是 Object.defineProperty,这是 Vue 2.0 进行双向数据绑定的写法。在 Vue 3.0 中,它使用 Proxy进行数据劫持。

为什么 Vue 3.0 中使用 Proxy 了?

  1. Vue 中使用 Object.defineProperty 进行双向数据绑定时,告知使用者是可以监听数组的,但是只是监听了数组的 push()、pop()、shift()、unshift()、splice()、sort()、reverse()这八种方法,其他数组的属性检测不到。
  2. Object.defineProperty只能劫持对象的属性,因此对每个对象的属性进行遍历时,如果属性值也是对象需要深度遍历,那么就比较麻烦了,所以在比较 Proxy 能完整劫持对象的对比下,选择 Proxy
  3. 为什么 Proxy 在 Vue 2.0 编写的时候出来了,尤大却没有用上去?因为当时 es6 环境不够成熟,兼容性不好,尤其是这个属性无法用polyfill来兼容。(polyfill 是一个 js 库,专门用来处理 js 的兼容性问题-js 修补器)

猜你喜欢

转载自blog.csdn.net/m0_37686205/article/details/89003190