learn-vue-02

在上一篇中简单的实现了Vue 响应式的依赖收集和触发,详情点击 learn-vue-01

但我们只是将依赖放在一个数组里面,虽然好理解但却不好维护,本节我们来实现一个可维护依赖的类。

确定功能

类的属性:

target: 函数,存放需要添加的依赖

实例的属性及方法:

subs:Array,存放依赖

addSub:Function,添加依赖

removeSub:Function,删除依赖

notify:Function,执行依赖

实现

封装 Dep类,进行依赖维护。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Dep {
// static target = null

constructor() {
this.subs = []
}

addSubs(sub) {
this.subs.push(sub)
}

removeSubs(sub) {
const index = this.subs.indexOf(sub)
if (index > -1) {
this.subs.splice(index, 1)
}
}

notify(newVal, oldVal) {
this.subs.forEach(func => func(newVal, oldVal))
}
}

Dep.target = null

对上篇中的 defineReactive进行改进:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const defineReactive = function (obj, key, val) {
const dep = new Dep()
Object.defineProperty(obj, key, {
configurable: true,
enumerable: true,
get() {
if (Dep.target) {
dep.addSubs(Dep.target)
}
return val
},
set(newVal) {
if (newVal !== val) {
dep.notify(newVal, val)
}
val = newVal
}
})
}

调用 defineReactive 函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const obj = {}
defineReactive(obj, 'name', 'jack')

Dep.target = (newValue, oldValue) =>
console.log('第一个依赖函数,新值为:' + newValue)
obj.name
// jack

Dep.target = (newValue, oldValue) =>
console.log('第二个依赖函数,新值为:' + newValue)
obj.name = 'ross'
obj.name
// 第一个依赖函数,新值为:ross
// ross

Dep.target = null
obj.name = 'titanic'
obj.name
// 第一个依赖函数,新值为:titanic
// 第二个依赖函数,新值为:titanic
// titanic

上面的代码还是存在两个问题:

  1. 虽然对添加依赖和处理依赖进行了解耦,但还是不完全的解耦,在执行依赖仍需传入新值和旧值。
  2. 可以看到我们并没有去使用 removeSub 方法去移除依赖,因为移除依赖一般都是在外部执行了,但我们目前是将 Dep的实例放在defineReactive内部,所以外部还是不能移除已经没有用的依赖。

要解决上面两个问题,需要使用 Vue 中的 Watch 类处理,这个之后再说。

查看相关代码

0%