探讨Vue 数据监测原理-第三节-展开介绍 Vue中监测-【对象】数据的原理

探讨一下Vue 数据监测的原理

尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通
Vue 教程 https://cn.vuejs.org/v2/guide/
MDN Web Docs 社区 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object

本次探讨的第三个章节

第三节:展开介绍 Vue中监测-【对象】数据的原理

1. 引子

  • 想要弄清楚 this.persons[0] = {id:"001",name:"马老师",age:"50",sex:'男'};
  • 为啥直接更新完整对象看到的却没有奏效,就需要知道以下两个问题
  • 问题1、vue 如何监测数组中数据改变的;
  • 问题2、vue 如何监测对象中数据改变的;
1.1. Vue 的数据代理
  • 先来看一下 vue 中是如何监测对象中数据改变的; Object.defineProperty() 就是使用数据代理 vm_data = data然后使用数据代理把数据把 _data 中属性值 代理到 vm 上,这样 vm 也就可以直接操作 _data 中的属性了
  • 如下 Vue 数据 代理图例在这里插入图片描述

2. 案例页面

<body>
    <div id="root">
        <h1>你好,{{name}}</h1>
        <hr/>
        <h2> 学校名称:{{schoolName}}</h2>
        <h2> 学校地址:{{schoolAddress}}</h2>
    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false //设置为 false 以阻止 vue 在启动时生成生产提示
        const vm = new Vue({
            el: "#root",
            data: {
                name: "安锐捷",
                schoolName: "天津安锐捷",
                schoolAddress: "普天科技园",
            },
            methods: {
               
            },
        })
  </script>
</body>
2.1. 加工数据data的流程

首先想一个问题?加工数据?为什么要在赋值之前进行一步加工数据的操作呢?
这是因为,经过数据加工之后,就会生成对应属性的getter/setter 方法,最终变为了响应式;数据改变页面也变。

  • 之前我们已经了解到,vm._data中的数据是由data直接赋值的,但是在之前其实还有一步操作:加工data操作,如下示例图示
    在这里插入图片描述
    • data 加工数据的流程
      1)、 修改_data中 name 属性值
      2)、 触发调用name 的setter方法 的调用
      3.)、setter 方法执行的过程中 触发调用->重新解析模板,渲染页面属性值
      如下流程示意图
      在这里插入图片描述
    • 整理一下流程顺序,整个工作流程如下
      • name 一改 setter 就调 ,
      • setter 一调 就重新解析模板;
      • 模板 一解析 就重新生成虚拟DOM
      • 新旧虚拟DOM 进行对比
      • 然后更新页面
      • 这就是一整套流程 在这里插入图片描述

3. 手动模拟数据监测

了解了data 加工过程,我们来手动模拟一下data 加工过程 。

3.1. 错误的监测 :开始手写了一个简单的代理,结果是错误的,记录一下
  • 示例
          let data ={
               name: "安锐捷",
               schoolName: "天津安锐捷",
               schoolAddress: "普天科技园",
           }	
           Object.defineProperty(data,'name',{
               get(){
                   return data.name;
               },
               set(value){
                   data.name = value;
               }
           })
           // 以上写法 添加属性会导致死循环
           // 当有人读取data 上的 name 属性时,就会触发 getter 操作返回data.name 
           // data.name 就会触发getter 操作,又会读取 data.name属性,这样就会导致一个死循环;
    
    在这里插入图片描述
    同理,这种写法下,setter 也是错误 ,就不多做分析了;
3.2. 正确写法的数据监测:
  • 构造Observer 对象,通过Observer 对象返回出数据
    <script type="text/javascript">
            let data ={
                name: "安锐捷",
                schoolName: "天津安锐捷",
                schoolAddress: "普天科技园",
            }
            // 正确的写法,先定义一个Observer 对象,通过Observer 对象返回出数据
            const obs = new Observer(data);
            console.log("obs:",obs);
            // Observer  具体实现
            function Observer(obj){
                // 汇总对象中所有的属性形成一个数组
                const keys = Object.keys(obj);
                //通过遍历 的方式,把对象中的属性 赋值给Observer
                keys.forEach((key)=>{
                    debugger
                    console.log("keys.forEach this: key",this,key); //关注 this key打印效果
                    Object.defineProperty(this,key,{
                        get(){
                            return obj[key];
                        },
                        set(val){
                            console.log(`${key}被修改了,我要去解析模板,生成虚拟DOM 我要去忙了……`);
                            obj[key] = val;
                        }
                    })
                })  
            }
    
    最终效果图如下
    在这里插入图片描述
  • 模拟vm 构造Vue 中实例对象 vm 同时模拟 _datadata
             // 正确的写法,先定义一个Observer 对象,通过Observer 对象返回出数据
             const obs = new Observer(data);
             console.log("obs:",obs);
    
             //定义vm 模拟 vue 中vm实例对象   
             let vm = {};
             vm._data = data = obs;
            
             function Observer(obj){
                // 汇总对象中所有的属性形成一个数组
                const keys = Object.keys(obj);
                //通过遍历 的方式,把对象中的属性 赋值给Observer
                keys.forEach((key)=>{
                    console.log("keys.forEach this: key",this,key);
                    Object.defineProperty(this,key,{
                        get(){
                            return obj[key];
                        },
                        set(val){
                            console.log(`${key}被修改了,我要去解析模板,生成虚拟DOM 我要去忙了……`);
                            obj[key] = val;
                        }
                    })
                })
             }
    	```
    
  • 核心代码
    		//定义vm 模拟 vue 中vm实例对象   
            let vm = {};
             vm._data = data = obs;
    
    打印查看构造的vm 实例,data 对象 效果
    在这里插入图片描述
    观察发现,vm_data data 都通过Observer 构造出了getter setter 方法
    测试效果
    在这里插入图片描述
    到此为止,模拟对象的数据检测就告一段落了,只要有了getter/setter 那么就可以进行下面的流程了
    - name 一改 setter 就调 ,
    - setter 一调 就重新解析模板;
    - 模板 一解析 就重新生成虚拟DOM
    - 新旧虚拟DOM 进行对比
    - 然后更新页面
    - 这就是一整套流程

唐-方棫 午醉醒来晚,无人梦自惊。 【失题】

中午小睡了一会,差点睡过了头 睡意朦胧间,想到了还有几篇文章没写完呢,真就是 无人梦自惊

创作不易,欢迎 多多点赞,收藏 有不到位的欢迎指证
邮箱:pymxb1991@163.com
微信:py_mxb

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值