在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 的具体实现,我们会在之后介绍。