欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

vue响应式原理及项目中常见的坑

程序员文章站 2023-11-15 15:53:58
Vue 的响应式原理是核心是通过 ES5 的保护对象的 Object.defindeProperty 中的访问器属性中的 get 和 set 方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检 ......

       vue 的响应式原理是核心是通过 es5 的保护对象的 object.defindeproperty 中的访问器属性中的 get 和 set 方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 wacher,观察者 wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 dom 树,vue 框架会遍历并对比新虚拟 dom 树和旧虚拟 dom 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真实 dom 树上。
vue响应式原理及项目中常见的坑

 

          虚拟dom (virtaul dom): 用 js 对象模拟的,保存当前视图内所有 dom 节点对象基本描述属性和节点间关系的树结构。用 js 对象,描述每个节点,及其父子关系,形成虚拟 dom 对象树结构。

 

项目中常遇到的关于vue响应式的记录与总结:

因为只要在 data 中声明的基本数据类型的数据,基本不存在数据不响应问题,所以重点介绍数组和对象在vue中的数据响应问题,vue可以检测对象属性的修改,但无法监听数组的所有变动及对象的新增和删除,只能使用数组变异方法及$set方法。

1. 向响应式的数组或者对象中修改已有的属性的方法

      当想要修改对象或者属性,并非新增属性时,一个已经在 data 中声明过的响应式数据,可以直接操作改变,数据改变会经过上图的步骤,触发视图改变。直接obj.xxx = xxx 即可,数组除外,但是后台传过来的 json 数组,数组中嵌套的对象也可以直接修改数组中的对象,因为 object.defindeproperty 的缺陷导致无法监听数组的变动,但始终会深度遍历data中数据,给数组中嵌套的对象添加上 get 和 set 方法,完成对对象的监听。

2. 向响应式的数组或者对象中新增一个响应式的属性的方法this.$set()或者数组变异方法

      即使是一个后台传过来的 json 数组,也可以使用this.$set向数组中的其中一个对象中添加一个响应式的属性,例如 this.$set(arr[0], 'xxx', xxx) 。或者使用数组变异方法例如splice,更多数组变异方法可以参考vue文档。

3. data中声明过的数组或者对象,整体替换数组或者对象保持响应式

      向响应式的数组和对象替换为新的响应式数据,可直接复制,因为data中声明的数据已经添加了访问器属性setter,当重新赋值一个新的堆内存地址时,该数组或者对象也会被循环遍历添加访问器属性,所以也是有响应式的。

vue响应式原理及项目中常见的坑

4.  vue无法监听对象的新增和删除,直接通过obj.xxx = xxx新增一个没有的属性,修改当前组件的一个响应式的数据重新触发当前组件re-render,可以让非响应式数据也保持更新状态(特殊情况) 。

         给一个数据添加一个非响应式的数据,例如一个已经在data中声明过的数据obj,obj.xxx=xxx,新增一个原本没有的数据,当你继续修改组件中一个其他的响应式数据,该obj也会同步更新到最新的数据另一种情况,当你向一个对象或者数组中同时增加一个响应式和非响应式数据,非响应式数据也会同步更新到页面。例如修改页面的其他响应式数据或者 this.$forceupdate()。

vue响应式原理及项目中常见的坑

图中this.haveselectedpeople是data中声明过的一个空数组,此时用非变异方法foreach循环数组向每一项添加三个非响应式数据和两个响应式数据,可以使添加的非响应式数据也有实时响应的效果,不建议这样做,因为会使代码难以理解,不过向数组中的每一项循环添加属性使用this.$set是可以经常利用的。

 

object.defindproperty虽然能够实现双向绑定了,但是还是有缺点,只能对对象的属性进行数据劫持,所以会深度遍历整个对象,不管层级有多深,只要数组中嵌套有对象,就能监听到对象的数据变化无法监听到数组的变化,proxy就没有这个问题,可以监听整个对象的数据变化,所以下个vue版本会用用proxy代替definedproperty