数据双向绑定原理?
Vue双向数据绑定过程中,这边数据改变了怎么通知另一边改变?
Vue数据响应式就是:数据变化更新视图,视图变化更新数据。
Vue数据响应式是通过数据劫持+发布订阅模式来实现的。通过数据劫持侦测数据变化;通过发布订阅模式进行依赖收集与视图更新。
Vue2的数据劫持就是利用了js原生提供的Object.defineProperty()方法。通过这个方法来劫持data对象中各个属性的getter和setter,在数据变动时就通知订阅者Watcher,订阅者就会触发它的update方法,对视图进行更新。
vue2的数据响应式缺点:①监听不到数组值的变化;②监听不到对象属性的新增或删除。
解决方案:使用Vue.set (vm.$set)、Vue.delete (vm.$delete)这些API
解除响应式:对数据进行深拷贝,或者使用Object.freeze()这个API对数据进行冻结。
在Vue2底层中它具体是通过实现Observe、Dep、Watcher、Compile这四个类来完成双向绑定原理的:
- Observe:用于进行数据劫持,就是把data对象的每个属性通过Object.defineProperty()转换为带有getter和setter的属性。实现对data数据的劫持监听。
- Dep:负责依赖收集和发布通知。里面通过数组储存所有Watcher,当Observe侦测到数据变动就立即调用Dep.notify(),遍历数组中的Watcher,并调用Watcher中的update方法。
- Watcher:主要用于触发执行更新渲染。Dep中收集依赖,就是收集Watcher。当Watcher中的update方法被调用时就会触发Compile中的patch()给真实Dom打补丁,更新相应视图。
- Compile:主要工作是解析模板指令,将模板中的指令替换成数据。对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,一旦数据有变动,收到通知,更新视图。
数据劫持:Object.defineProperty()
发布订阅模式:
订阅者Watch --- 【负责订阅一些事件】
- update():当事件发生时具体要做的事情
发布者Dep --- 【负责依赖收集和发布通知】
- subs数组:存储所有的订阅者Watch实例
- addSub():添加观察者到subs数组中
- notify():发布订阅的方法,当事件发生就调用所有观察者的update()方法
订阅者就是Dom元素
VUE2:Object.defineProperty()
VUE3:Proxy proxy代理是es6推出的新api,可以弥补vue2数据响应式的缺点,所以vue3用proxy替换了Object.defineProperty()
视图变化更新数据(事件监听),数据变化更新视图(数据劫持 + 发布订阅模式)
其实只有对象和数组才会有这种删除和增加的操作,而其他的字符串等都是直接赋值修改的,getter/setter都是能检测到的,所以observe对象和数组的时候会创建一个dep,用来收集订阅和发布更新