前言
Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。这使得状态管理非常简单直接,本文,我们将研究一下 Vue 响应式系统的一些原理
图示
主要成员
在响应式原理中,Observe、Dep、Watcher 这三个类是构成完整原理的主要成员,Compile则是负责解析vue el
模板中引用的属性
new Vue({
el:'#app',
data:{
name:"why",
age:18
}
})
<div id="app">
{{name}}
{{name}}
{{age}}
{{age}}
</div>
-
Observer监听劫持所有的vue
data
属性
当你把一个普通的 JavaScript 对象传入 Vue 实例作为data
选项,Vue 将遍历此对象所有的 property,并使用Object.defineProperty
把这些 property 全部转为 getter/setter。
每一个属性就有一个Dep对象,Dep对象存放着所有watcher
name->Dep对象-subs[watcher1,watcher2]
age->Dep对象-subs[watcher1,watcher2]
-
Dep/Watcher
当我们改变data中属性的值时,比如 name:'why' 改为 name:'cobe'时,会触发Observer
对我们data属性的监听,监听到name属性
发生变化,会调用name属性
对应的Dep对象
的notify函数
,notify遍历所有watcher属性,调用update
去更新视图
this.name='cobe';
-
Compile解析vue
el
模板中引用的属性,如我们多次使用了date中的name和age属性
解析el时
1.每使用的一个属性就创建一个watcher,watcher会加到对应的dep的subs中;
2.会根据el内容初始化到View(界面显示)
<script>
//发布者
class Dep {
constructor() {
this.subs = []; //全部订阅者watcher
}
//记录(添加)订阅者watcher
addSub(watcher) {
console.log(`记录订阅者: ${watcher}`)
this.subs.push(watcher)
}
//通知变化
notify(key) {
this.subs.forEach(item => {
if (item.name == key) {
item.update();
}
})
}
}
// 订阅者
class Watcher {
constructor(name) {
this.name = name;
}
//更新视图------代码待补充
update() {
console.log(this.name + '发生update,执行更新视图')
}
}
const obj = {
name: "cc",
age: 18
}
const dep = new Dep();
Object.keys(obj).forEach(key => {
let value = obj[key];
Object.defineProperty(obj, key, {
set(newValue) {
if(value===newValue){
return false;
}
console.log(`监听: ${key} 值由 ${value} 改为 ${newValue}`)
//通知变化
dep.notify(key)
value = newValue;
},
get() {
console.log(`获取: ${key} 值`)
/*
添加订阅者
*/
const watcher = new Watcher(key);
dep.addSub(watcher)
return value
}
})
})
obj.name;
obj.age;
obj.name='aaa';
obj.age=19;
</script>
运行结果: