Vue 的响应式原理
1. 前言
-
当
data
中的数据发生改变,Vue内部是如何监听message数据的改变?使用
Object.defineProperty
-----> 监听对象属性的改变 -
当数据发生改变,Vue是如何知道要通知哪些人?哪些页面进行更新?
使用 发布订阅者模式 实现
2. 过程
2.1 首先new Vue()
new Vue({
el: "#app",
data: {
name: "fct",
age: 18
}
})
2.2 针对data
中的数据
利用Object.defineProperty
对data对象中的数据进行重构,设置get
、set
。用以监听数据的改变。
new Observer(data); // 处理data
// 观察者
class Observer {
constructor(data) { // data 即为 Vue中data对象数据
this.data = data;
Object.keys(data).forEach(item => {
this.defineReactive(this.data, key, data[key])
})
}
defineReactive(obj, key, val) {
// 一个属性 key ,对应一个 Dep 对象
const dep = new Dep();
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
set(newValue) {
if (newValue === value) {
return;
}
value = newValue;
// 通知订阅者对象watcher,进行视图更新
dep.notify();
},
get() {
// 添加到订阅者队列
if (Dep.target) {
// target 即为watcher
dep.addSub(Dep.target);
}
return value;
}
})
}
}
-
每个data中的属性都对应一个Dep对象(
dependence
依赖),其中有属性:subs
(订阅者subscriber
),该属性对应的值是数组,数组中每一项为watcher
对象(观察者)。class Dep { constructor() { this.subs = [] // 存放watcher对象数组 } notify() { // 通知subs对象中所有watcher,进行更新 // watcher 对象都有update方法进行视图更新 this.subs.forEach(sub => { sub.update(); }) } addSub(sub) { // 添加 watcher对象 this.subs.push(sub); } }
2.3 针对 el
模板
解析模板中何处使用了data
中的数据,为每一处使用创建一个watcher
对象。并将对象推入到相应data
数据的Dep
对象的subs
数组中。
new Compiler('el', this); //处理el('#app')
class Compiler { //编译
constructor() {
// ....
new Watcher(); //编译时找到{{}}使用了data中的属性,新建watcher对象
}
}
class Watcher {
constructor() {
Dep.target = this; //1. 设置target,getter中if满足条件
this.update(); //2. 进订阅者数组
Dep.target = null; //3. 赋空
}
update() {
// 更新视图, this.node.nodeValue设置值
this.node.nodeValue = this.vm[this.name]; // this.vm即为Vue实例
// this.vm[this.name]取属性值,会调用data对象属性的getter,然后添加进sub数组
}
}