前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >理清vue2,vue3响应式原理

理清vue2,vue3响应式原理

作者头像
qiangzai
发布2022-09-21 09:18:57
4550
发布2022-09-21 09:18:57
举报
文章被收录于专栏:强仔博客

vue2和vue3响应式原理

vue2响应式原理

  1. 对象类型:通过Object.defineProperty(obj,property,descriptor)对属性的读取、修改进行拦截(数据劫持)。 obj绑定属性的目标对象property绑定的属性名descriptor属性(配置)对象
  2. 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
  3. 存在问题:
    • 新增属性、删除属性, 界面不会更新。
    • 直接通过下标修改数组, 界面不会自动更新。
代码解构

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

代码语言:javascript
复制
      // 设置源数据
      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

代码语言:javascript
复制
<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对象上面,从而达到响应数据

代码语言:javascript
复制
      // 设置源数据
      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的情况下,也是可以实现数据响应的

代码语言:javascript
复制
      // 设置源数据
      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
代码语言:javascript
复制
    <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使用比较好,相关内容较多,请各位自行查阅吧,如有出错,欢迎各位大佬指出,小弟必将虚心求教

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-08-117,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • vue2和vue3响应式原理
    • vue2响应式原理
      • 代码解构
      • v2响应式demo
    • vue3响应式原理
      • 代码解构
      • v3响应式demo
    • 总结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档