vue 双向数据绑定的原理

vue2.0 通过ES5: Object.defineProperty

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>vue2.0 数据双向绑定</title>
  </head>
  <body>
    姓名:<span id="spanName"></span>
    <br />
    <input type="text" id="inpName" />

    <script>
      /**
       * 通过ES5: Object.defineProperty
       * 数据改变,触发视图重新渲染。视图改变,触发数据改变。
       */
      let obj = {
        name: "",
      };
      /**
       * 简单实现深克隆
       * 接收改变后的值,避免死循环
       */
      let newObj = JSON.parse(JSON.stringify(obj));

      // 监听 obj 中 name 值的改变
      Object.defineProperty(obj, "name", {
        get() {
          return newObj.name; // 通过新的变量接收改变后的值,避免出现死循环的情况
        },
        set(val) {
          if (val === newObj.name) return;
          newObj.name = val;
          observer();
        },
      });

      // 观察者
      function observer() {
        spanName.innerHTML = obj.name; // 获取 obj值的时候会触发 get() 获取最新的值
        inpName.value = obj.name;
      }

      // observer();

      /**
       * 模拟修改数据
       * 数据的更改影响视图
       */
      setTimeout(() => {
        obj.name = "测试";
      }, 1000);

      /**
       * 监听 input 文本框的改变
       * 视图的改变影响数据
       * 相当于 v-model
       */
      inpName.oninput = function () {
        obj.name = this.value;
      };

      /**
       * 存在的问题:
       * 1.需要对原始数据进行克隆
       * 2.需要分别给对象中每一个属性设置监听
       */
    </script>
  </body>
</html>

vue3.0 通过ES6 Proxy 拦截器实现数据双向绑定

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>vue3.0 实现数据的双向数据绑定</title>
  </head>
  <body>
    姓名:<span id="spanName"></span>
    <br />
    <input type="text" id="inpName" />

    <script>
      /**
       * 通过ES6 Proxy 拦截器实现数据双向绑定
       * 1.不需要克隆
       * 2.不需要对对象的每个属性设置监听
       */
      let obj = {};
      /**
       * 监听整个对象
       * 不需要指定属性
       * 把当前对象的所有属性都监听(截持)了
       */
      obj = new Proxy(obj, {
        get(target, prop) {
          // target 就是 obj
          return target[prop];
        },
        set(target, prop, value) {
          target[prop] = value;
          observer();
        },
      });

      // 观察者
      function observer() {
        spanName.innerHTML = obj.name; // 获取 obj值的时候会触发 get() 获取最新的值
        inpName.value = obj.name;
      }

      /**
       * 模拟修改数据
       * 数据的更改影响视图
       */
      setTimeout(() => {
        obj.name = "测试";
      }, 1000);

      /**
       * 监听 input 文本框的改变
       * 视图的改变影响数据
       * 相当于 v-model
       */
      inpName.oninput = function () {
        obj.name = this.value;
      };
    </script>
  </body>
</html>

.

原文地址:https://www.cnblogs.com/crazycode2/p/13458160.html