- 作者:老汪软件技巧
- 发表时间:2024-10-13 11:03
- 浏览量:
1.ref
在 Vue 3 中,ref 的实现主要依赖于 Proxy 对象和 Dep(依赖)机制来追踪依赖关系和触发更新。不过,对于基本数据类型,ref 并不会直接使用 Proxy,因为 Proxy 需要一个对象作为目标,而基本数据类型本身不是对象。相反,ref 会创建一个包含 value 属性的对象来包装基本数据类型,从而使其能够被响应式系统所管理。
下面是一个简化的 ref 源码分析:
源码位置
ref 的定义位于 @vue/reactivity 包中的 src/ref.ts 文件中。
源码分析
// @vue/reactivity/src/ref.ts
import { isObject, hasOwn, isFunction } from '@vue/shared'
import { track, trigger } from './effect'
import { ReactiveFlags, Target, TargetWithMemo } from './reactive'
import { EffectScope, recordEffectScope } from './effectScope'
import { toRaw, toReactive } from './reactive'
export interface Ref {
value: T
__v_isRef: true
}
export function ref(value: T): Ref<UnwrapRef> {
return createRef(value, false)
}
function createRef(rawValue: unknown, shallow: boolean): Ref<unknown> {
if (isRef(rawValue)) {
return rawValue
}
const r: Ref<any> = {
__v_isRef: true,
_rawValue: rawValue,
_value: shallow ? rawValue : toReactive(rawValue),
get value() {
track(r, TrackOpTypes.GET, 'value')
return r._value
},
set value(newVal) {
if (hasChanged(r._rawValue, newVal)) {
r._rawValue = newVal
r._value = shallow ? newVal : toReactive(newVal)
trigger(r, TriggerOpTypes.SET, 'value', newVal)
}
}
}
return r
}
关键点解析
createRef 函数:
get value 方法:
set value 方法:
小结
通过这种方式,Vue 3 能够有效地管理基本数据类型的响应式变化。
2.toReactive
在 Vue 3 中,toReactive 函数用于将一个值转换为响应式对象。toReactive 主要通过 reactive 函数来实现,而 reactive 函数的核心是使用 Proxy 对象来拦截对对象属性的访问和修改,从而实现响应式。
源码位置
toReactive 和 reactive 的定义位于 @vue/reactivity 包中的 src/reactive.ts 文件中。
源码分析toReactive 函数
// @vue/reactivity/src/reactive.ts
import { isObject, hasOwn, isFunction } from '@vue/shared'
import { reactiveMap, readonlyMap } from './baseHandlers'
import { ReactiveFlags, Target, TargetWithMemo } from './reactive'
import { EffectScope, recordEffectScope } from './effectScope'
import { toRaw, toReactive } from './reactive'
export function toReactive(value: T): T {
return isObject(value) ? reactive(value) : value
}
export function reactiveextends object>(target: T): UnwrapNestedRefs {
// 如果目标已经是响应式对象,直接返回
if (isReactive(target)) {
return target
}
// 如果目标是只读对象,返回只读版本
if (isReadonly(target)) {
return readonly(target)
}
// 创建响应式代理
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers,
reactiveMap
)
}
createReactiveObject 函数
function createReactiveObject(
target: Target,
isShallow: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMapany >
) {
if (!isObject(target)) {
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
// 查找缓存的代理对象
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
// 创建新的代理对象
const proxy = new Proxy(target, collectionHandlers)
proxyMap.set(target, proxy)
return proxy
}
关键点解析
toReactive 函数:
reactive 函数:
createReactiveObject 函数:
处理基本数据类型和引用数据类型
引用数据类型:
小结
通过这种方式,Vue 3 能够高效地管理和追踪复杂数据结构的变化,同时保持对基本数据类型的简洁处理。