数据响应式原理
看源码的时候思考以下问题
- vm.msg ={ count: 0 } 重新给属性赋值,是否是响应式
- vm.arr[0] = 4 给数组元素赋值,视图是否会更新
- vm.arr.length = 0 修改数组的length,视图是否会更新
- vm.arr.push(4) 视图是否会更新
响应式整体流程
我们已经知道了整体的流程,在_init
方法中,我们可以看到调用了initState
方法。在initState
方法中,我们可以看到
export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
// 这里就是响应式的入口了
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {}, true /* asRootData */)
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
我们只要看当opts.data
存在的时候就可以了。调用了initData
,省略一些判断代码我们可以看到,这里就是循环data
的key
, 通过proxy
将所有的key
代理到了vm
中。最后调用了observe(data)
进入data
的响应式流程
function initData (vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {}
const keys = Object.keys(data)
let i = keys.length
while (i--) {
const key = keys[i]
if (!isReserved(key)) {
proxy(vm, `_data`, key)
}
}
// observe data
observe(data, true /* asRootData */)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export function observe (value: any, asRootData: ?boolean): Observer | void {
if (!isObject(value) || value instanceof VNode) {
return
}
let ob: Observer | void
// 是否存在ob,如果存在则直接赋值返回
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__
} else if (
shouldObserve &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
// 创建一个Observer对象
ob = new Observer(value)
}
// ob.vmCount++
if (asRootData && ob) {
ob.vmCount++
}
// 返回对象
return ob
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25