教程
理清vue2,vue3响应式原理
278

vue2和vue3响应式原理

vue2响应式原理

  1. 对象类型:通过Object.defineProperty(obj,property,descriptor)对属性的读取、修改进行拦截(数据劫持)。

    obj绑定属性的目标对象
    property绑定的属性名
    descriptor属性(配置)对象
  2. 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
  3. 存在问题:

    • 新增属性、删除属性, 界面不会更新。
    • 直接通过下标修改数组, 界面不会自动更新。

代码解构

对新对象p进行数据劫持,当访问到name属性时,会执行get()方法,从而返回源对象person的name属性。当修改p的name属性时,会执行set()方法,此时源对象的person中name属性就会同步更改

      // 设置源数据
      const person = {
        name: "玩偶姐姐",
        age: 24,
        hobby: ["抽烟", "喝酒", "打豆豆"],
      };
      const p = {};
      Object.defineProperty(p, "name", {
        // 属性值
        // value: 12,
        //控制属性是否可以枚举,默认值是false
        // enumerable: true,
        //控制属性是否可以被修改,默认值是false
        // writable: true,
        //控制属性是否可以被删除,默认值是false
        configurable: true,
        // 当有人读取p的name属性时执行
        get() {
          console.log("读取了person的name属性");
          return person.name;
        },
        // 当有人修改p的name属性时执行
        set(value) {
          console.log("修改了person的name属性");
          person.name = value;
        },
      });

注意:在给对象设置 get 和 set 存取数据时,就不能设置属性值 value 和可读性 wriable,两者不可共存,使用 get 和 set 作为替代对属性进行读和取,所以只需要设置一个允许删除即可

v2响应式demo

通过object.defineproperty()来实现一个简单的响应式demo

<div>请输入 : <input type="text" /></div>
    <br />
    <textarea cols="30" rows="10"></textarea>
    <script>
      const obj = {
        demo: "",
      };
      const newObj = {};
      Object.defineProperty(newObj, "demo", {
        configurable: true,
        get() {
          console.log("读取到到了数据");
          return obj.demo;
        },
        set(value) {
          console.log(`我同步了新数据${value}`);
          obj.demo = value;
          document.querySelector("input").value = value;
          document.querySelector("textarea").value = value;
        },
      });
      document.querySelector("input").addEventListener("input", function () {
        newObj.demo = this.value;
      });
      document.querySelector("textarea").addEventListener("input", function () {
        newObj.demo = this.value;
      });
    </script>

vue3响应式原理

  1. 通过Proxy(代理): new Proxy(target, handler),拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。

    target要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
    handler以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
  2. 通过Reflect(反射): 对源对象的属性进行操作。

代码解构

通过proxy对person的代理,从而拦截对象的读取,修改删除属性操作,然后再通过p映射到person对象上面,从而达到响应数据

      // 设置源数据
      const person = {
        name: "玩偶姐姐",
        age: 24,
        hobby: ["抽烟", "喝酒", "打豆豆"],
      };
      const p = new Proxy(person, {
        //有人读取p的某个属性时调用
        get(target, propName) {
          console.log(`有人读取了p身上的${propName}属性`);
          return Reflect.get(target, propName);
        },
        //有人修改p的某个属性、或给p追加某个属性时调用
        set(target, propName, value) {
          console.log(`有人修改了p身上的${propName}属性,我要去更新界面了!`);
          Reflect.set(target, propName, value);
        },
        //有人删除p的某个属性时调用
        deleteProperty(target, propName) {
          console.log(`有人删除了p身上的${propName}属性,我要去更新界面了!`);
          return Reflect.deleteProperty(target, propName);
        },
      });

当然,如果在不用reflect的情况下,也是可以实现数据响应的

      // 设置源数据
      const person = {
        name: "玩偶姐姐",
        age: 24,
        hobby: ["抽烟", "喝酒", "打豆豆"],
      };
      const p = new Proxy(person, {
        get(target, propName) {
          console.log(`有人读取了p身上的${propName}属性`);
          return target[propName];
        },
        set(target, propName, value) {
          console.log(`有人修改了p身上的${propName}属性,我要去更新界面了!`);
          return (target[propName] = value);
        },
        deleteProperty(target, propName) {
          console.log(`有人删除了p身上的${propName}属性,我要去更新界面了!`);
          return delete target[propName];
        },
      });

v3响应式demo

    <div>请输入 : <input type="text" /></div>
    <br />
    <textarea cols="30" rows="10"></textarea>
    <script>
      const obj = {
        demo: "",
      };
      const newObj = new Proxy(obj, {
        // 有人读取p的某个属性时调用
        get(target, propName) {
          console.log(`有人读取了p身上的${propName}属性`);
          return Reflect.get(target, propName);
        },
        //有人修改p的某个属性、或给p追加某个属性时调用
        set(target, propName, value) {
          console.log(`我同步了新数据${value}`);
          Reflect.set(target, propName, value);
          document.querySelector("input").value = value;
          document.querySelector("textarea").value = value;
        },
        //有人删除p的某个属性时调用
        deleteProperty(target, propName) {
          return Reflect.deleteProperty(target, propName);
        },
      });

      document.querySelector("input").addEventListener("input", function () {
        newObj.demo = this.value;
      });
      document.querySelector("textarea").addEventListener("input", function () {
        newObj.demo = this.value;
      });

总结

以上就是v2v3响应式方面本人总结的内容,至于v3方面的为什么proxy要搭配reflet使用比较好,相关内容较多,请各位自行查阅吧,如有出错,欢迎各位大佬指出,小弟必将虚心求教


  • 上一篇
  • 下一篇
  • 添加评论
    评论(3)
    Rose
    Rose

    我已经落后了,哈哈

    在下厦门人

    主题不错,求推荐

    淄博漏水检测

    感谢分享,赞一个

    welcome to qiangzai blog