为什么要收集依赖?
举个例子:
// 假设我们有多个Vue对象
// 这个全局变量需要在所有Vue对象都能进行展示
let obj = {
count:0
}
let vm1 = new Vue({
template:`<div>{{count}}</div>`,
data:obj
})
let vm2 = new Vue({
template:`<div>{{count}}</div>`,
data:obj
})
//这时候我们要对象全局变量进行修改
//修改后还需要让count知道是谁依赖了自己,然后count变更的时候通知依赖自己的对象(vm1、vm2)
//最后vm1、vm2进行视图更新
obj.count = 1;
下面来实现依赖收集:
// Dep订阅者
class Dep{
constructor(){
this.watcherArr = []; // 存放依赖
}
addWatcherArr(watcherArr){ // 添加依赖
if(watcherArr){
this.watcherArr.push(watcherArr)
}
}
notify(){ // 更新视图
this.watcherArr.forEach(obj=>{
obj.update();
})
}
}
// 观察者
class Watcher{
constructor(){
// 该对象被创建时赋值到Dep._this,获取属性时会用到
Dep._this = this;
}
update(){
console.log('视图更新了!')
}
}
function defineReactive(obj,key,val){
const dep = new Dep(); // 创建订阅者,好进行收集依赖、更新视图
Object.defineProperty(obj,key,{
enumerable: true,
configurable: true,
get:()=>{
dep.addWatcherArr(Dep._this); // 收集依赖
return val;
},
set:(newVal)=>{
if(newVal===val) return;
val = newVal;
dep.notify(); // 数据变更后通知更新视图
}
})
}
function observers(value){
if(!value || (typeof value !=="object")){return}
Object.keys(value).forEach(key=>{
return defineReactive(value,key,value[key]);
})
}
class Vue {
constructor(options){
this.data = options.data;
observers(this.data);
// 依赖收集的前提条件有两个:触发get方法、创建一个Watcher对象
// 以上两个条件已满足,这时候update方法更新了
new Watcher();
this.data.age = 18; // 触发set
// 这里只是通过打印的方式触发get方法读取、实际的话只要通过render()进行渲染,所有的依赖都会被读取
this.data.age; // 触发get方法
console.log(this.data.age);
}
}
const app = new Vue({
data:{
name:'张三',
age:25
}
})
Dep._this = null; // 清空上次依赖