前言
Vue 3 从现象到本质的思维旅程
第一阶段:重新理解 Composition API 的设计哲学
- ref vs reactive:为什么需要两套响应式?
深层响应式 vs 引用包裹:API 设计背后的取舍 - toRef 与 toRefs:解构响应式的“隐形陷阱”
为什么const { count } = state会丢失响应性? - shallowRef 与 shallowReactive:浅层响应式的用途
何时该“放过”深层数据?性能优化的真实场景 - triggerRef:手动触发 shallowRef 更新
被动更新之外,如何主动“唤醒”一个 ref? - customRef:手写一个防抖的 ref
暴露 track 与 trigger,实现自定义响应式逻辑 - ref 自动解包:规则是什么?边界在哪?
为什么不需要.value?模板 vs JS 的差异
第二阶段:穿透响应式系统的核心机制
- reactive 的本质:Proxy 拦截了什么?
get、set、has、ownKeys如何构建响应式链条 - readonly:只读代理的实现原理
如何拦截所有修改操作并抛出警告? - proxyRefs:setup 返回值的自动解包机制
Vue 如何在return { count }时自动处理.value? - isRef、isReactive、isReadonly:类型检测的底层逻辑
它们是如何通过__v_isRef这类私有标志判断的? - unref 与 toRaw:穿透响应式代理的“逃生舱”
toRaw如何拿到原始对象?什么场景下必须使用?
第三阶段:深入生命周期与渲染机制
- onMounted 的执行时机:比你想象的更晚
它真的在 DOM 挂载后执行吗?与nextTick的关系 - onRenderTracked 与 onRenderTriggered
如何监听依赖收集与触发过程?用于性能调优 - render 函数与 VNode 的创建过程
h()返回了什么?VNode 如何描述一个组件? - patch 过程:diff 算法的核心逻辑
key 的作用、双端对比、快速路径优化(sameVNodeType) - 组件更新:props 变化如何触发子组件更新?
从trigger到queueJob,再到scheduler
第四阶段:解构编译器与运行时的协作
- 模板编译:从
<div></div>到 render 函数
AST 转换、静态提升、缓存优化是如何工作的? - 静态节点提升(Static Hoisting)
为什么有些节点只创建一次?_hoisted_1是什么? - 事件缓存(Event Caching)
@click="onClick"如何避免每次渲染都创建新函数? - v-model 的编译原理
v-model如何被转换为modelValue+onUpdate:modelValue? - v-if vs v-show:编译结果有何不同?
条件渲染的两种策略:销毁重建 vs display 切换
第五阶段:探索高级响应式与状态管理
- computed 的惰性求值机制
为什么它不会立即执行?effect的 lazy 选项 - watch 与 watchEffect:侦听器的两种哲学
显式依赖 vs 副作用收集,谁更适合你的场景? - watch 的源(source)可以是哪些类型?
ref、reactive、getter、数组、字符串路径 - watch 的 flush 时机:pre、post、sync
何时同步执行?何时延迟到组件更新后? - provide / inject:跨层级响应式的实现原理
如何绕过 props 传递,实现“全局”注入?响应式穿透
第六阶段:揭秘底层设计与边界场景
- 组件实例的生命周期:从 create 到 unmount
_isMounted、_isDestroyed等内部状态的作用 - setupContext 中的 expose:如何控制组件暴露的属性?
expose()如何影响$refs的访问? - 异步组件与 suspense 的协作机制
defineAsyncComponent如何与<Suspense>配合? - Teleport 的实现原理:如何把 DOM 挂载到任意位置?
move()操作如何动态迁移 VNode? - KeepAlive 缓存机制:如何保存组件状态?
include、exclude、max的实现,activated/deactivated钩子