开门见山,先来一下尤雨溪的vue Mastery里面实现的最简单的响应式版本(思想一样,具体代码我小改一手,更好理解)
const trackMap = new WeakMap();
let activeEffect = null;
// obj => key => effect
const reactive = (obj) => {
return new Proxy(obj, {
get(target, key, receiver) {
// track-跟踪
trackMap.set(target, { [key]: { effects: [] } });
const current = trackMap.get(target);
current[key].effects.push(activeEffect);
return Reflect.get(target, key, receiver);
},
set(target, key, value) {
target[key] = value;
// trigger-触发
trackMap.get(target)?.[key]?.effects?.forEach((effect) => effect());
return Reflect.set(target, key, value);
},
});
};
const effect = (effect) => {
activeEffect = effect;
effect();
activeEffect = null;
};
let obj = reactive({ a: 1, b: 2 });
effect(() => {
console.log(obj.a);
});
obj.a = 2;
obj.b = 3;
//print
1
2
很好理解,重点就是get的时候把函数effect函数收集起来,set时候再触发
但是真正的实现肯定不会这么简单,很多源码解析讲到这里就结束了,或者再给你讲点实现,但是我想告诉你的是,怎么从这个思想,到一整个响应式的包.
响应式的包一共有11个文件,看看都是什么
- 前两个文件都是处理函数,输出的是对应到proxy里面的一些方法例如: get,set,deleteProperty, has,ownKeys
这些方法会根据响应式对象的不同有很多变化,例如处理数组,处理循环嵌套,readonly和shallow浅层响应,
collectionHandlers, 处理map这种不同的对象
- computed和deferredComputed用来封装对外的计算属性api
- dep文件用来处理依赖相关的几个对象,还有effcect缓存的功能
- effect文件用来处理依赖收集和触发effect的代码, effectScope用来开启一个作用域手动控制effect的开始和失效,这是一个vue3.2的新功能
- operations用来定义了两个枚举对象,看一眼就知道干嘛用的了
export const enum TrackOpTypes {
GET = 'get',
HAS = 'has',
ITERATE = 'iterate'
}
export const enum TriggerOpTypes {
SET = 'set',
ADD = 'add',
DELETE = 'delete',
CLEAR = 'clear'
}
-
Reactive 和ref是平时最常用的两个api,用来组装功能并且对外暴露api使用
-
Warning 用来拼接警告信息
这个包其实就是对响应式思想干了几件事
抽象 ! 组合 ! 处理边界条件! 代理更多的属性! 组装API
例如: baseHandler 就是为了输出这个方法以及对不同的对象类型进行不同的函数处理
export const mutableHandlers: ProxyHandler<object> = {
get,
set,
deleteProperty,
has,
ownKeys
}
// 只读对象处理器
export const readonlyHandlers: ProxyHandler<object> = {
get: readonlyGet,
set(target, key) {
if (__DEV__) {
warn(
`Set operation on key "${String(key)}" failed: target is readonly.`,
target
)
}
return true
},
deleteProperty(target, key) {
if (__DEV__) {
warn(
`Delete operation on key "${String(key)}" failed: target is readonly.`,
target
)
}
return true
}
}
// 浅层响应处理器
export const shallowReactiveHandlers = /*#__PURE__*/ extend(
{},
mutableHandlers,
{
get: shallowGet,
set: shallowSet
}
)
// Props handlers are special in the sense that it should not unwrap top-level
// refs (in order to allow refs to be explicitly passed down), but should
// retain the reactivity of the normal readonly object.
export const shallowReadonlyHandlers = /*#__PURE__*/ extend(
{},
readonlyHandlers,
{
get: shallowReadonlyGet
}
)
源码其实很好看懂,只是第一眼不知道每一块代码的目的是什么,或者是某一块的代码在处理什么问题,有人告诉你都是什么之后就很好调试了
希望看完的人把vue源码克隆下来,花一两个小时看一下,说不定什么时候调试就用到了