响应式原理
作用
Vue的响应式可以实现数据和视图相关联,由数据驱动视图的更新
原理
Vue2的响应式原理
- Vue2的响应式原理依靠的是Object.defineProperty()方法
const obj={}
Object.defineProperty(obj, "b", { //b为要定义或修改的属性键
get() { //访问属性时触发
return bValue;
},
set(newValue) { //修改属性时触发
bValue = newValue;
},
enumerable: true, //enumerable设置该属性是否在对象的属性枚举中出现
configurable: true, //configurable设置该属性是否可以被更改或者删除
});
- 当在一个位置获取对象的属性 obj.b 时,会调用 getter 方法,数据会收集在一个集合中,当这个属性更新时,就可以通过这个集合获取到依赖这个属性的位置,并驱动视图更新
- 当更新属性的值时,会触发 setter 方法,通知收集的依赖项更新,从而更新视图
Vue3的响应式原理
- Vue3的响应式原理依靠的是 Proxy对象 ,Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
- 与 Vue2 相比,Vue2 依靠的 Object.defineProperty ,无法监听数组基于下标的修改,也不支持 Map、Set 等,而 Proxy 解决了这些问题,并且可以代理整个对象。
- 不论是在组件的 data 选项中返回一个普通的 js 对象,还是创建了一个 reactive 对象,Vue3 都会将其包裹在一个带有 get 和 set 处理程序的 Proxy 对象中
- vue3 中,通过 track 的处理器函数来收集依赖,通过 trigger 的处理器函数来派发更新,每个依赖的使用都会被包裹到一个副作用函数 effect 中,而派发更新后就会执行副作用函数,这样依赖的值就被更新了
function reactive(obj){
return new Proxy(obj,{
//get拦截对象属性的读取
get(obj,prop,receiver){ //prop为待拦截属性名,receiver为proxy实例
const value=Reflect.get(obj,prop,receiver);
// 如果属性值是对象,递归地返回代理对象
return typeof value === 'object' ? reactive(value) : value;
},
//set拦截对象的属性赋值操作
set(obj,prop,value,receiver){ //value为新值
const res=Reflect.set(obj,prop,value,receiver);
return res;
}
})
}
双向绑定
作用
实现数据模型 Model 和视图 View 的同步关系,当其中一个改变,另一个也会同步更新,常用指令为 v-model
原理
先来看看 vue 中的双向绑定的流程:
- new Vue() 执行初始化,对 data 执行响应化处理,这个过程发生在 Observe 中
- 编译模板,找到动态绑定的数据,从 data 中获取并初始化视图,这个过程发生在 Compile 中
- 同时定义一个更新函数和 Watcher ,数据变化时Watcher 会调用更新函数
- 由于data的某个key在一个视图中可能出现多次,所以每个key都需要一个管家 Dep 来管理多个 Watcher
- data 数据变化时,会首先找到对应的 Dep,通知所有 Watcher 执行更新函数
依赖收集
视图中用到 data 的某个 key ,叫做依赖,同一个 key 可能出现多次,每次都需要收集出来用一个 Watcher 维护它们,此过程为依赖收集,多个 Watcher 需要一个 Dep 来管理,更新时由 Dep 统一通知
举例:
初始化视图时读取某个 key ,例如 name ,会创建一个 watcher ,由于触发了 name 的 getter 方法, watcher 会被添加到 name 对应的 Dep 中,当 name 更新时, setter 触发,就可以通过对应的 Dep 通知其管理的所有 watcher 更新
参考文章:https://vue3js.cn/interview/vue/bind.html#%E4%BA%8C%E3%80%81%E5%8F%8C%E5%90%91%E7%BB%91%E5%AE%9A%E7%9A%84%E5%8E%9F%E7%90%86%E6%98%AF%E4%BB%80%E4%B9%88
如有错漏,请指正