Vue3 源码
响应式系统
Vue 3 的响应式系统主要位于 packages/reactivity
目录下。这个模块负责实现数据的响应式特性,包括 ref、reactive、computed 等。
src/index.ts
是 reactivity 模块的入口文件,导出了主要的响应式 API。
src/reactive.ts
,这个文件实现了 reactive 函数,用于将普通对象转换为响应式对象。
packages/reactivity/src/reactive.ts
export function reactive(target: object) {
// if trying to observe a readonly proxy, return the readonly version.
if (isReadonly(target)) {
return target;
}
return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
}
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
if (!isObject(target)) {
if (__DEV__) {
warn(`value cannot be made ${isReadonly ? 'readonly' : 'reactive'}: ${String(target)}`);
}
return target;
}
// target is already a Proxy, return it.
// exception: calling readonly() on a reactive object
if (target[ReactiveFlags.RAW] && !(isReadonly && target[ReactiveFlags.IS_REACTIVE])) {
return target;
}
// target already has corresponding Proxy
const existingProxy = proxyMap.get(target);
if (existingProxy) {
return existingProxy;
}
// only specific value types can be observed.
const targetType = getTargetType(target);
if (targetType === TargetType.INVALID) {
return target;
}
const proxy = new Proxy(target, targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers);
proxyMap.set(target, proxy);
return proxy;
}
reactive 函数首先判断传入的对象是否为只读对象,如果是,则直接返回该对象。如果不是只读对象,则调用 createReactiveObject 函数,该函数会根据传入的对象类型(普通对象 、数组、Map 等)选择不同的代理处理器。
代理处理器包括 baseHandlers 和 collectionHandlers,它们是响应式系统实现的核心。
src/baseHandlers
处理对象属性的读写操作,例如 get 和 set 方法src/collectionHandlers
处理集合类的读写操作,例如 Map 和 Set 等
在代理处理器中,通过拦截器机制来实现数据的响应式。例如,在 get 方法中,会调用 track
函数,用于收集依赖关系,在 set 方法中,会调用 trigger
函数,用于触发依赖更新。
src/ref.ts
:实现了 ref 和 shallowRefsrc/computed.ts
:实现了 computedsrc/watch.ts
:实现了 watch 和 watchEffectsrc/effect.ts
:实现了 effect 函数,用于创建响应式副作用函数,这是依赖收集和触发更新的核心机制
src/ref.ts
export function ref(value?: unknown) {
return createRef(value, false);
}
export function shallowRef(value?: unknown) {
return createRef(value, true);
}
function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue;
}
return new RefImpl(rawValue, shallow);
}
class RefImpl<T = any> {
constructor(value: T, isShallow: boolean) {}
get value() {}
set value(newValue) {}
}