Vue核心⑨(数据监测原理)

网友投稿 275 2022-09-16

Vue核心⑨(数据监测原理)

文章目录

​​问题引入​​​​如何实现针对对象进行数据监测​​​​Vue.set()的使用​​​​如何实现针对数组进行数据监测​​​​数据监测总结​​

问题引入

我们前面知道只要data中的数据发生变化,那么Vue会重新解析模板更新数据。那么这一定是决定的吗?我们可以看看下面的例子:

我们借用原来的列表案例,对其中的一项进行修改:

如果只是对其中对象的属性进行修改,是奏效的:

人员列表

  • {{p.name}}-{{p.age}}-{{p.sex}}

而如果是对其中的对象整体修改,会发现不奏效:

人员列表

  • {{p.name}}-{{p.age}}-{{p.sex}}

如何实现针对对象进行数据监测

在前面我们说到数据代理的时候,我们当时说Vue会将​​data​​​中的数据放到​​_data​​中去,然后再将_data中的数据进行代理。其实在Vue将​​data​​中的数据放到​​_data​​之前,Vue对data中的数据进行了加工,而这个加工的步骤就是Vue实现数据监测的关键。

我们可以来验证一下: 对于如下代码(简单的在data中放了两个数据):

{{name}}

{{province}}

我们可以看到:

在​​vm._data​​中我们可以发现里面的东西并不完全跟data中的一样,说明确实做了一个加工。而这个加工的内容就是多出来的方法。也就是说Vue为每一个数据添加了get和set方法。

Vue通过这个加工就做成了响应式(图中的reactive其实就是响应的意思)。当我们修改数据的时候,就会执行其setter方法,而这个setter方法里面就有一个调用。他让我们的模板重新解析。

完整流程: 改变数据 => 调用setter => 重新解析模板 =>生成新的虚拟DOM => 新旧DOM对比 =>更新页面

其实我们可以尝试粗略的去实现一下数据监视:

如上的代码只考虑到了一层的情况,也就是说如果出现对象里面还有属性的情况,它发生改变我们是监视不到的。

Vue底层使用递归,它会一直往下找,直到找到某一个东西不再是对象。

例如,如果data是这样的:

let data = { name:'CSDN', address:'北京', a:{ b:1 } }

使用如上代码是提供不了b的getter和setter的:

同时Vue里面还使用了数据代理,上面的代码是没有用到的。我们修改数据只能通过​​_data​​​,而不能直接通过​​data​​如果我们将一个对象藏在了数组里面,Vue也可以把它找出来,并提供相应的getter和setter:

Vue.set()的使用

我们现在有一个需求,人物的性别不能确定,我们想要在后期添加,并且能让页面显示。我们的思路是直接添加任务的性别属性,这样就能显示出来了。但这样真的可以吗?

注意: Vue不会显示一切为Undefine的值 我们可以衍生一下假设a为对象,b为属性(并不存在的)。​​​a.b​​​如果a存在b不存在,Vue不会报错,并且不显示undifined 如果直接访问b,b不存在,则Vue会报错。

学生信息

姓名:{{student.name}}

性别:{{student.sex}}

年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}

朋友们

  • {{f.name}}--{{f.age}}

然后我们给性别属性赋值:

发现页面并没有发生变化:

我们查看vm可以发现,导致页面没有变化的原因是因为新添加的性别属性根本没有getter和setter:

也就是说后添加的属性Vue是不会为其做响应式的。也就是说我们需要响应式的数据最好一开始就在源码中定义好。当然Vue也给我们提供了方法去解决后期添加的数据没有响应式的问题,它就是​​Vue.set()​​

我们可以尝试一下:

同时这种方法在vm身上也有一个,它的名字叫​​$set()​​,我们也可以试一下:

但是这个方法也有局限性!例如:

使用这个方法vm以及vm身上的根数据不允许作为target。也就是说只能在data中的对象中才能添加属性,直接在data中加不行。

如何实现针对数组进行数据监测

我们在以上案例的基础上,为student中添加一个属性hobby,其值为数组:

我们接下来将其爱好用列表进行呈现,代码如下:

学生信息

姓名:{{student.name}}

性别:{{student.sex}}

年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}

朋友们

  • {{f.name}}--{{f.age}}
  • {{h}}

接下来我们对hobby列表中的其中一项进行修改,发现页面并没有进行更新。

我们查看vm,发现Vue并没有为数组中的每一项配置getter和setter方法:

那么我们怎么能让Vue知道我们修改了数组中的数据呢?

其实Vue中规定了只有使用如下的几种方法对数组进行修改的时候,这种变化才能被监测得到:

push() 向数组的末尾添加元素pop() 删除数组的最后一个元素shift() 删除数组的第一个元素unshift() 在数组的开头添加新元素splice() 用于添加和删除元素sort() 对数组进行排序reverse() 对数组进行反转

例如:

那么Vue是如何检测到我们使用了这种办法的呢?这要依赖于一种独特的​​包装技术​​ – 包装数组身上的常用的修改数组的方法。

其实我们使用的push,与我们Array.push不是一个方法:

我们原来使用的push是沿着原型链往上找,在原型对象上找到的push。而这里的push是Vue给我们写的push,Vue在这个push方法中为我们做了两件事:

调用正常数组的push方法重新解析模板,生成虚拟DOM········

数据监测总结

代码如下:

学生信息









姓名:{{student.name}}

年龄:{{student.age}}

性别:{{student.sex}}

爱好:

  • {{h}}

朋友们:

  • {{f.name}}--{{f.age}}

什么是数据劫持? 就是将data中的每一个属性都遍历了一遍,形成getter、setter的形式,这种行为就是数据劫持。 例如我们修改一个属性,会立马被setter劫持到。劫持之后它会正常的帮我们修改数据,另一个就是帮我们重新解析模板。 数据劫持和数据代理都离不开Object.defineProperty()

总结:

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Vue核心④(计算属性)
下一篇:坚果站着饿死、魅族一加妥协,智能手机“小而美”时代终结!
相关文章

 发表评论

暂时没有评论,来抢沙发吧~