概述
Vue源码部分讲的依赖收集和触发比较复杂,不容易理解。今天我把它最简化讲出来。如果你有收获,请给小弟一个赞。
前期准备
- 声明一个Map做储蓄;
- current用来传递数据;
- data数据备用;
const map = new Map();
let current = null;
const data = {
name: 'madapao',
age: 18,
sex: '男',
}
复制代码
创建一个Watcher类
deps数组收集依赖,add方法添加依赖。
class Watcher {
constructor() {
this.deps = [];
}
add(dep) {
this.deps.push(dep)
}
}
复制代码
收集和触发
对data中的数据进行劫持:
- get:判断map中有没有这个key,如果没有,就新建一个watcher,把current(current是什么等访问的时候就知道了)加进行watcher的deps中,每个key在map中对应一个watcher。如果已经有了,直接拿出来wathcer,把current加进行watcher的deps中。
- set:拿出map中key对应的watcher,把它deps中的方法全部执行一次。
Object.keys(data).forEach(key => {
Object.defineProperty(data, key, {
get() {
if (map.has(key)) {
const watcher = map.get(key);
watcher.add(current);
map.set(key, watcher)
} else {
const watcher = new Watcher();
watcher.add(current);
deps.set(key, watcher);
}
},
set() {
if (map.has(key)) {
map.get(key).deps.forEach(fn => fn())
}
}
})
})
复制代码
使用
在执行getAgeName方法,暂时把getAgeName赋值给current,使用data中数据key时。就会触发key的get。把getAgeName放进key对应watcher的deps中。
当修改key的值时,就会触发key对应watcher收集到的所有方法。
function getAgeName() {
current = getAgeName;
console.log('getAgeName执行了')
return `${data.name}'今年'${data.age}岁。`
}
function getSexName() {
current = getSexName;
console.log('getSexName执行了')
return `${data.name}'是一个'${data.sex}人。`
}
getAgeName();
getSexName();
data.name = 'mahaha';
复制代码
全部代码
const deps = new Map();
let current = null;
class Watcher {
constructor() {
this.deps = [];
}
add(dep) {
this.deps.push(dep)
}
}
const data = {
name: 'madapao',
age: 18,
sex: '男',
}
Object.keys(data).forEach(key => {
Object.defineProperty(data, key, {
get() {
if (deps.has(key)) {
const watcher = deps.get(key);
watcher.add(current);
deps.set(key, watcher)
} else {
const watcher = new Watcher();
watcher.add(current);
deps.set(key, watcher);
}
},
set() {
if (deps.has(key)) {
deps.get(key).deps.forEach(fn => fn())
}
}
})
})
function getAgeName() {
current = getAgeName;
console.log('getAgeName执行了')
return `${data.name}'今年'${data.age}岁。`
}
function getSexName() {
current = getSexName;
console.log('getSexName执行了')
return `${data.name}'是一个'${data.sex}人。`
}
getAgeName();
getSexName();
data.name = 'mahaha';
复制代码