文章目录
探讨一下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 进行对比
- 然后更新页面
- 这就是一整套流程
- data 加工数据的流程
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 同时模拟 _data、data
// 正确的写法,先定义一个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 实例,data 对象 效果//定义vm 模拟 vue 中vm实例对象 let vm = {}; vm._data = data = obs;
观察发现,vm_data data 都通过Observer 构造出了getter setter 方法
测试效果
到此为止,模拟对象的数据检测就告一段落了,只要有了getter/setter 那么就可以进行下面的流程了
- name 一改 setter 就调 ,
- setter 一调 就重新解析模板;
- 模板 一解析 就重新生成虚拟DOM
- 新旧虚拟DOM 进行对比
- 然后更新页面
- 这就是一整套流程
唐-方棫 午醉醒来晚,无人梦自惊。 【失题】
中午小睡了一会,差点睡过了头 睡意朦胧间,想到了还有几篇文章没写完呢,真就是 无人梦自惊
创作不易,欢迎 多多点赞,收藏 有不到位的欢迎指证
邮箱:pymxb1991@163.com
微信:py_mxb