双向绑定是指数据模型(Module)和视图(View)之间的双向绑定关系,数据变化更新视图,视图变化更新数据。
其原理是采用数据劫持结合发布者-订阅者模式的方式来实现。
Vue中先遍历data选项中所有的属性(发布者)用Object.defineProperty劫持这些属性将其转为getter/setter。读取数据时候会触发getter。修改数据时会触发setter。
然后给每个属性对应new Dep(),Dep是专门收集依赖、删除依赖、向依赖发送消息的。先让每个依赖设置在Dep.target上,在Dep中创建一个依赖数组,先判断Dep.target是否已经在依赖中存在,不存在的话添加到依赖数组中完成依赖收集,随后将Dep.target置为上一个依赖。
组件在挂载过程中都会new一个Watcher实例。这个实例就是依赖(订阅者)。Watcher第二参数式一个函数,此函数作用是更新且渲染节点。在首次渲染过程,会自动调用Dep方法来收集依赖,收集完成后组件中每个数据都绑定上该依赖。当数据变化时就会在seeter中通知对应的依赖进行更新。在更新过程中要先读取数据,就会触发Wacther的第二个函数参数。一触发就再次再次自动调用Dep方法收集依赖,同时在此函数中运行patch(diff运算)来更新对应的DOM节点,完成了双向绑定。
\
主要成员:Observe、Dep、Watcher
- Observe:响应式原理的入口,根据渲染类型处理观测逻辑
- Dep:依赖收集器,属性都有一个Dep,方便发生变化时能够找到对应的依赖触发更新
- Watcher:用于执行更新渲染,组件会拥有一个watcher,常说的收集依赖,就是收集watcher
Observe步骤:
- 为观测的属性添加
__ob__属性,它的值等于this,即当前的Observe实例 - 为数组添加重写的数组方法,重写的目的在于调用时,进行更新渲染
- 观测数组内的数据,Observe内部会调用new Observe,形成递归观测
- 观测对象数据,defineReactive为数据定义get和set,即数据劫持
Dep步骤:
- 数据依赖手机的主要方法:Dep.target是一个watcher实例
- 添加watcher倒数组中,即添加依赖
- 属性变化时,会调用notify,通知每一个依赖更新
- Dep.target用来记录watcher实例,是全局危矣的,主要作用是为了在手机依赖的过程中找到对应的watcher
watcher步骤:
-
this.getter存储的是更新视图的函数
-
watcher存储depends,同时dep也存储watcher,进行双向记录
-
触发更新,异步更新会调用run方法更新页面
-
入口文件地址:/src/core/instance/state.js\
作用:获取data,设置代理,启动响应式observe
- 响应式:/src/core/observer/index.js
- 数组响应式:/src/core/observer/array.js
作用:为数组中的7个可以改变内容的方法定义拦截器
html代码:
响应式过程视频:youtu.be/2NclszR08hk