前言:前段时间拜读了vue-next部分源码(v3.0.0-alpha.8),想在vue3.0正式版发布前了解下vue3.0的一些新特性,本文仅作为自己的学习记录和总结,欢迎拍砖探讨。
准备工作:
1、TypeScript学习,2019年是TS的一年,Vue 3全部采用TS构建,学会TS很有必要。
2、ES6+相关知识,如 Proxy 、 Reflect 等。
正文:
目录:
├── packages
│ ├── compiler-core // 编译器核心
│ ├── compiler-dom // dom解析&编译
│ ├── compiler-sfc // 文件编译系统│ ├── compiler-ssr // 服务端渲染
│ ├── reactivity // 数据响应
│ ├── runtime-core // 虚拟DOM渲染-核心
│ ├── runtime-dom // dom即时编译
│ ├── runtime-test // 测试runtime
│ ├── server-renderer // ssr
│ ├── shared // 帮助
│ ├── size-check // runtime包size检测
│ ├── template-explorer
│ └── vue // 构建vue主要模块解析-响应式
众所周知,在 Vue 3 中使用了 Proxy 替换了原先的 Object.defineproperty 来实现数据响应,本文主要截取部分源码,按照个人理解添加相关注释,有注释不清晰的地方望指正。
数据响应模块
使用方法:
const obj = reactive({ num: 0 })
// 当给obj.num 赋值会触发回调
effect(() => {
console.log(obj.num)
})
obj.num = 1reactive原理解析:
export function reactive(target: object) {
// 如果代理的对象是readonly的则直接return readonly对象的代理
if (readonlyToRaw.has(target)) {
return target
}
// 如果代理的对象被标记为readonly则调用readonly返回其代理
if (readonlyValues.has(target)) {
return readonly(target)
}
//如果是ref对象直接返回
if (isRef(target)) {
return target
}
// 调用createReactiveObject创建reactive对象
return createReactiveObject(
target,
rawToReactive,
reactiveToRaw,
mutableHandlers,
mutableCollectionHandlers
)
}接着分析createReactiveObject方法-该方法主要用于创建响应式代理对象
function createReactiveObject(
target: unknown,
toProxy: WeakMap<any, any>,
toRaw: WeakMap<any, any>,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>
) {
// 如果非对象 直接return并且dev环境下打印警告
if (!isObject(target)) {
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
// 目标对象可观察,直接返回已创建的代理
let observed = toProxy.get(target)
if (observed !== void 0) {
return observed
}
// 目标对象已经有代理,直接返回Proxy代理
if (toRaw.has(target)) {
return target
}
// 目标对象不可观察,直接返回目标对象
if (!canObserve(target)) {
return target
}
// 创建响应式代理,Set、Map、WeakMap、WeakSet的响应式对象handler与Object、Array的响应式对象handler不同,要分开处理
const handlers = collectionTypes.has(target.constructor)
? collectionHandlers : baseHandlers
// 创建代理
observed = new Proxy(target, handlers)
// 更新rawToReactive、reactiveToRaw的映射
toProxy.set(target, observed)
toRaw.set(observed, target)
return observed
}Object和Array的响应式对象handler,也就是baseHandlers.ts文件
主要分析createGetter()和createSetter()
function createGetter(isReadonly = false, shallow = false) {
return function get(target: object, key: string | symbol, receiver: object) {
// 对Array单独处理
if (isArray(target) && hasOwn(arrayInstrumentations, key)) {
return Reflect.get(arrayInstrumentations, key, receiver)
}
// 通过Reflect拿到原始对象的的get
const res = Reflect.get(target, key, receiver)
// 如果是内置方法,不处理
if (isSymbol(key) && builtInSymbols.has(key)) {
return res
}
// 官方标记TODO 应该是严格模式下返回只读对象
if (shallow) {
// track方法用于收集依赖
track(target, TrackOpTypes.GET, key)
return res
}
// 如果是ref对象-展开,只用于判断对象,不用于判断数组
if (isRef(res) && !isArray(target)) {
return res.value
}
// 收集依赖
track(target, TrackOpTypes.GET, key)
// 拿到结果,判断是否嵌套对象,如果嵌套则递归调用reactive,避免循环调用
return isObject(res) ? isReadonly
? readonly(res) : reactive(res)
: res
}
}Set、Map、WeakMap、WeakSet的代理暂且不表。
小结:
本文主要对响应式核心原理进行理解,笔者也将持续关注Vue3.x后续版本的更新,欢迎大家讨论。