Vue核心原理之数据的深度响应
1.问题的引入
-
为什么点击下面的
button
界面会出现自增?<div id="example-2"> <simple-counter></simple-counter> </div> Vue.component('simple-counter', { template: '<button v-on:click="counter += 1">{{ counter }} </button>', data: function () { return { counter: 0 } } }) new Vue({ el: '#example-2'})
- 为什么数据发生变化之后,视图就发生变化?
- 本文从三个方面来理解Vue处理深度响应的原理:
-
数据定义
; -
数据绑定
; -
数据响应
;
2.数据的定义
- 组件中定义数据
{counter:0}
; - 初始化过程中,会执行
observe(data, this)
; - 在
observe()
过程中会将data
这个对象劫持,通过Object.defineProperty
将data
上所有的属性绑定上getter
和setter
函数;(这是针对对象,对于数组,Vue
通过改写数组的原生方法来劫持); - 通俗的说就是只要谁获取了
counter
的值就会触发getter()
;要是谁改变了counter
的值就会触发setter()
;比如上述代码中的button
绑定{{count}}
的时候一定会触发getter()
;如果是count
的值发生改变就一定会触发setter()
3.数据绑定
- 在页面元素
button
中绑定{{count}}
; - 在编译过程中,针对这个
button
会产生一个Watcher(vm, exp, cb(newValue,oldValue))
,vm
是Vue
对象,exp
是数据绑定的数据;cb()
的逻辑是用来更新页面。现在的问题是如何将数据的变化和Watcher
关联起来。 -
在这里用到了一个重要的思想就是
发布订阅模式
;Watcher
初始化的时候会将Dep.target
设置为this
,也就是Watcher
自己,同时会触发count
的getter
方法,getter
里面会调用Dep
的depend
方法,depend
方法会调用Watcher
的addDep
方法,addDep
方法就是将Watcher
自己存放在Dep
的事件池里面。class Dep { constructor() { this.id = uid++; this.subs = []; } addSub(sub) { this.subs.push(sub) } depend() { if (Dep.target) { Dep.target.addDep(this) } } removeSub(sub) { let ind = this.subs.findIndex(sub); this.subs.splice(ind, 1) } notify() { this.subs.forEach(sub => sub.update()) } } Dep.target = null;
4.数据响应
- 当发生点击事件的时候,
count
的值改变,会触发setter
里面的方法,这个方法会调用dep.notify()
;它会告知Dep的事件池里的存放的Watcher
去执行它的update()
方法;Watcher
的update()
方法;这个方法里面会获取count
的新的值,给它的回调cb()
,去更新视图。 - 这三个过程就是下面
Vue
官方给出的示意图的含义。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。