在Vue中,数据的变更会出发DOM的变化
1 | <div id="app" @click="changeMsg"> |
1 | var app = new Vue({ |
在我们修改this.message的时候,模板对于的插值也会渲染成新数据,这是怎么做到的?
什么是响应式对象
之前了解过Vue实现响应式是利用了Object.defineProperty
Object.defineProperty
1 | Object.defineProperty(obj, prop, descriptor) |
一旦对象有了getter和setter,就可以称之为响应式对象
响应式对象的创建
在Vue中,我们需要观测的对象主要是props和data中的数据
之前我们已经知道,在Vue创建的过程中调用了Vue.prototype._init方法,其中调用initState就是初始化数据,其中会有对数据响应式的处理
1 | // src/core/instance/state.js |
initProps
首先看initProps
1 | function initProps (vm: Component, propsOptions: Object) { |
props 的初始化主要过程,就是遍历定义的 props 配置。遍历的过程主要做两件事情:一个是调用 defineReactive 方法把每个 prop 对应的值变成响应式,可以通过 vm._props.xxx 访问到定义 props 中对应的属性。对于 defineReactive 方法,我们稍后会介绍;另一个是通过 proxy 把 vm._props.xxx 的访问代理到 vm.xxx 上。
initData
1 | function initData (vm: Component) { |
初始化data主要做两件事,对定义的data返回对象进行遍历,把每个值vm._data.xxx代理到vm.xxx上,调用observe观测整个data的变化,把data变成响应式
observe
用来监测数据的变化
1 | // src/core/observer/index.js |
observe方法对传入的value做一些校验,最终会当做参数生成一个Observer对象实例,构造Observer实例过程中会给value添加上__ob__属性
Observer
1 | export class Observer { |
Observer实例化了Dep对象、把自身实例对象添加到数据对象value的__ob__属性上、最终调用walk方法,而在walk方法中,对数据对象的每一个属性调用defineReactive方法,在之前的initProps方法中,对每一个porps的属性也调用了defineReactive方法
defineReactie
defineReactive 的功能就是定义一个响应式对象,给对象动态添加 getter 和 setter,它的定义在 src/core/observer/index.js 中:
1 | export function defineReactive ( |
defineReactive 函数最开始初始化 Dep 对象的实例,接着拿到 obj 的属性描述符,然后对子对象递归调用 observe 方法,这样就保证了无论 obj 的结构多复杂,它的所有子属性也能变成响应式的对象,这样我们访问或修改 obj 中一个嵌套较深的属性,也能触发 getter 和 setter。最后利用 Object.defineProperty 去给 obj 的属性 key 添加 getter 和 setter。而关于 getter 和 setter 的具体实现,我们会在之后介绍。