0%
Pinia 状态管理
发表于 分类于 Vue
本文字数: 7k 阅读时长 ≈ 6 分钟
Vue Router 4 路由
发表于 分类于 Vue
本文字数: 14k 阅读时长 ≈ 12 分钟
【面试速答版】
Q1: “Vue Router 4 相比 3 有哪些主要变化?”
创建从 new VueRouter() 变为 createRouter({ history: createWebHistory() })。全面拥抱 Composition API——useRouter 和 useRoute。导航守卫 next() 变为可选,不 return 即放行,不再有”忘记调用 next 页面卡死”的 bug。移除了 <transition> + <keep-alive> 的旧嵌套用法,改用 <router-view v-slot> 灵活控制。TypeScript 类型全面增强。动态路由 API 更完善(addRoute/removeRoute)。
Vue2 vs Vue3 — 全方位异同对比
发表于 分类于 Vue
本文字数: 5k 阅读时长 ≈ 5 分钟
【面试速答版】
Q1: “Vue3 到底好在哪?你有 Vue2 迁移到 Vue3 的经验吗?”
Vue3 是 Vue2 的架构重构而非简单升级。四个维度:响应式——Proxy 替代 Object.defineProperty,解决了数组/新增属性监听问题;API 范式——Composition API + composables 替代 mixin,解决逻辑复用冲突;性能——编译时 PatchFlag + 静态提升 + Block Tree,渲染性能提升 1.3-2 倍;生态——Pinia 替代 Vuex(去掉了烦人的 mutations),Vite 替代 Webpack。迁移经验:Options API 和 Composition API 可以混用,建议渐进式迁移——先升级构建工具和依赖库,再逐组件改造。
Q2: “Vue2 和 Vue3 有哪些破坏性变更?迁移时需要特别注意什么?”
必知变更:v-model 默认 prop 从 value + input 变为 modelValue + update:modelValue;.sync 修饰符废弃,用多 v-model 替代;$on/$off/$once 移除(EventBus 不再内置,推荐 mitt);filters 移除(用 computed 或方法代替);$listeners 合并到 $attrs;v-if 优先级高于 v-for(Vue2 相反);生命周期 beforeDestroy → beforeUnmount、destroyed → unmounted。迁移建议:先安装 @vue/compat 兼容模式,逐一修复控制台的废弃警告,再移除兼容层。
Q3: “Vue2 项目如何迁移到 Vue3?必须全部重写吗?”
不需要全部重写。Options API 在 Vue3 中完全兼容,Composition API 可以混用。推荐的迁移步骤:① 升级构建工具到 Vite 或 Webpack 5 并安装 Vue3;② 安装 @vue/compat(Vue3 的 Vue2 兼容模式);③ 一条条修复兼容警告(先解决 filters 和 v-model,再处理生命周期改名和 EventBus);④ 移除 @vue/compat,使用原生 Vue3;⑤ 新组件用 <script setup> 写,旧组件逐步改造。核心原则:基础设施先升级,业务代码逐步改,不急着重写所有组件。
【深入理解版】
1. 这个知识点要解决什么问题?
Vue2 发布于 2016 年,随着前端发展,它的几个设计逐渐暴露出问题:
- Object.defineProperty 的局限——无法监听数组下标修改、新增/删除属性,需要 hack(重写 7 个数组方法)和
Vue.set/Vue.delete。 - Options API 在复杂组件中的维护问题——200 行的组件,功能逻辑分散在 data/methods/computed/watch 四个区域。
- mixin 的缺陷——命名冲突、来源不明、隐式依赖。
- Tree-shaking 不支持——即使不用过渡动画、指令,打包时也被包含。
- 全局 API 污染——
Vue.mixin影响所有实例。
Vue3 在 2020 年发布,2022 年成为默认版本,重写了核心模块但保持了 90% 以上的 API 兼容。
2. 核心差异对比
2.1 创建实例
1 | // Vue2 — 全局 API 可能导致冲突 |
2.2 响应式系统
1 | // Vue2 — 需要额外 API 处理新增/删除 |
2.3 生命周期对照
| Vue2 | Vue3 | 说明 |
|---|---|---|
| beforeCreate / created | setup() | setup 在 beforeCreate 之前执行 |
| beforeMount | onBeforeMount | 设名 |
| mounted | onMounted | hooks 化 |
| beforeUpdate | onBeforeUpdate | hooks 化 |
| updated | onUpdated | hooks 化 |
| beforeDestroy | onBeforeUnmount | 更名,语义更清晰 |
| destroyed | onUnmounted | 更名 |
| errorCaptured | onErrorCaptured | hooks 化 |
2.4 模板语法
1 | <!-- Vue2 — 单根节点 --> |
1 | <!-- Vue2 v-model --> |
3. 迁移中的常见坑
坑 1:v-model 默认行为变化
Vue2 的 v-model="count" 对应 value prop 和 input 事件。Vue3 改为 modelValue prop 和 update:modelValue 事件。如果自定义组件升级到 Vue3 但没有改 props 声明,双向绑定功能会失效。
坑 2:filters 移除
1 | <!-- Vue2 --> |
坑 3:EventBus 移除
Vue2 中 new Vue() 作为事件总线 + $on/$off。Vue3 中不再支持。推荐:状态共享用 Pinia,跨组件事件通信用 mitt(200 字节)。
坑 4:$listeners 合并到 $attrs
Vue2 中 $attrs 只包含非 props 的 attribute,$listeners 包含所有监听器。Vue3 中两者合并到 $attrs,且 class 和 style 也包含在 $attrs 中。
4. 迁移策略
1 | Step 1: 升级构建环境 |
5. 对比总结
| 对比维度 | Vue2 (2016) | Vue3 (2020) |
|---|---|---|
| 响应式核心 | Object.defineProperty | Proxy |
| API 范式 | Options API | + Composition API |
| 逻辑复用 | mixin | composables |
| TypeScript | 困难 | 一等公民 |
| 渲染性能 | 全量递归 diff | PatchFlag + 静态提升 |
| 包体积 | ~30KB(不可摇树) | ~13KB(可摇树) |
| 多根节点 | 不支持 | Fragment 支持 |
| 状态管理 | Vuex(需 mutations) | Pinia(无 mutations) |
| 构建工具 | Webpack(默认) | Vite(官方推荐) |
6. 现代最佳实践(2024-2025)
- 新项目直接选 Vue3 + Vite + TypeScript + Pinia + Vue Router 4。
- 渐进式迁移——不必一次性重写所有组件。Options API 依然受支持,可以和 Composition API 混用。
- 放弃 mixin——所有 mixin 逻辑改为 composables(
useXxx函数)。 - 放弃 EventBus——状态共享用 Pinia,事件通信用 mitt。
- 利用
@vue/compat做平滑迁移——不要直接在旧项目上装 Vue3 原生版。
7. 常见疑问解答
Q:Vue3 中为什么把 beforeDestroy 改成 beforeUnmount?
A:语义更准确。destroy 在英文中暗示”彻底销毁”,而 React 也有类似生命周期方法。Vue 团队认为 unmount(卸载)更准确地描述了”组件从 DOM 树中移除”这个行为。同理 destroyed → unmounted。
Q:我能在 Vue2 项目中使用 Composition API 吗?
A:可以——安装 @vue/composition-api 插件后,Vue2 项目也能用 ref、reactive、computed、watch、onMounted 等。但有一些限制:① defineComponent 是零等的;② <script setup> 不可用(这是编译器特性,Vue2 编译器不支持);③ onUnmounted 在 Vue2 中映射为 destroyed。这只是一种过渡方案,最终还是需要迁移到 Vue3。
Q:@vue/compat 兼容模式会拖慢性能吗?
A:会有一点性能损耗,因为兼容层需要额外做 Vue2 API 的适配转换。但它只应该作为迁移过程的工具——你逐条修复废弃警告,修复一条就少一条兼容代码。当所有 warnings 都修完后,就可以移除 @vue/compat,使用原生 Vue3。不要长期在生产环境使用兼容模式。
关联知识点索引
- 所有 Vue3 文档(本目录)
- 所有 Vue2 文档(
../Vue2/)
Vue3 核心变化与 Composition API
发表于 分类于 Vue
本文字数: 7.1k 阅读时长 ≈ 6 分钟
【面试速答版】
Q1: “Vue3 对比 Vue2 有哪些核心变化?”
三大核心变化:响应式系统——用 Proxy 替代 Object.defineProperty,解决了 Vue2 无法监听数组下标修改、新增/删除属性、Map/Set 的问题,且性能更好。Composition API——把组件逻辑按功能组织而非按选项(data/methods/computed)分割,解决了 Vue2 mixin 的命名冲突和来源不明问题。编译器优化——引入 PatchFlag(编译时标记动态节点类型)、静态提升(静态节点提升到 render 外复用)、树摇(按需引入运行时 API),渲染性能提升约 1.3-2 倍。此外还新增了 Fragments(多根节点)、Teleport(传送门——把组件渲染到指定 DOM 位置)、Suspense(异步依赖统一管理)等特性。
Q2: “Composition API 解决了什么痛点?Vue2 的 Options API 有什么问题?”
Vue2 中一个 200 行的组件,逻辑分散在 data、methods、computed、watch 四个选项中——搜索功能相关的代码分散在四个地方,分页功能也是。你想理解”搜索”整个功能,要在文件内来回跳转。这就是”逻辑分散”问题。逻辑复用靠 mixin——但 mixin 有命名冲突(两个 mixin 都定义了 handleSearch)、来源不明(模板里的 handleSearch 是哪个 mixin 提供的?)、隐式依赖(mixin 依赖宿主组件的某个 data,但没有任何类型提示)。Composition API 让你按功能组织:搜索的逻辑写在一起,分页的逻辑写在一起,然后通过 composables(组合函数)把逻辑提取为可复用的 useSearch、usePagination,没有冲突、来源清晰。
Q3: “setup 和 script setup 是什么?ref 和 reactive 有什么区别?”
setup 是 Composition API 的入口函数,在组件创建前执行。<script setup> 是它的语法糖,编译后等价于 setup 函数,模板中直接使用顶层变量不需要 return。ref 和 reactive 都是创建响应式数据的方式:ref 通过 .value 访问/修改,适用于基础类型和需要重新赋值的变量;reactive 直接操作属性,适用于深层嵌套的对象。在模板中 ref 自动解包(不需要 .value),在 reactive 中也会自动解包。建议优先用 ref——赋值时不会丢失响应式,且解构时用 toRefs 即可。
【深入理解版】
1. 这个知识点要解决什么问题?
Vue2 当年(2016)的设计在现在看来有一些历史局限。用 Vue2 写过 300 行以上的组件可能都有这种体验:一个表格组件里同时有搜索、分页、筛选、导出四个功能,每个功能的数据在 data 中初始化、方法在 methods 中定义、计算属性在 computed 中。当你想理解”搜索”这个功能时,你需要在 created(初始化请求)、methods(搜索方法)、computed(搜索结果)、watch(搜索条件变化)之间来回跳转。这就是 Options API 的逻辑分散问题。
除此之外:Vue2 的响应式用 Object.defineProperty 在初始化时递归遍历 data 所有属性,导致两个问题——新增/删除属性无法监听(需要 Vue.set/Vue.delete)、数组下标修改无法监听。Vue3 用 Proxy 重写了响应式系统,同时引入了 Composition API 解决逻辑组织问题。
2. 核心原理/执行过程
2.1 createApp 替代 new Vue()
1 | // Vue2 — 全局 API 污染 |
createApp 返回一个应用实例,所有全局 API(mixin、component、directive)都挂在这个实例上,不影响其他 Vue 应用。这在微前端场景下很重要——两个子应用可以各有独立的 Vue 配置。
2.2 Composition API 的执行流程
1 | <script setup> 编译阶段 |
setup 执行时组件实例还没创建,所以 setup 中不能访问 this(this 是 undefined)。如果想在 setup 中获取当前组件实例,可以用 getCurrentInstance()(但很少需要这样做)。
2.3 ref 和 reactive 的底层关系
1 | import { ref, reactive } from 'vue' |
ref 的本质是:如果传入基础类型(string/number/boolean),把它包在一个 { value: ... } 对象中,然后让这个对象变成响应式的。如果传入对象,内部调用 reactive 处理。所以 ref(0) 和 reactive({ value: 0 }) 的本质是相同的。
模板中 ref 自动解包:
1 | <template> |
但不是所有地方都解包:
1 | const count = ref(0) |
3. 实际应用场景
场景1:useSearch composable(逻辑复用)
1 | // composables/useSearch.js |
1 | <script setup> |
这个 composable 封装了搜索的完整逻辑(防抖、请求、loading),任何需要搜索功能的组件直接引入使用,没有 mixin 的冲突问题。
场景2:Teleport 传送弹窗
1 | <!-- Modal.vue --> |
没有 Teleport 时,如果 Modal 在父组件中层级很深,父组件的 overflow: hidden、transform、z-index 都可能影响弹窗的显示。<Teleport to="body"> 把模板内容渲染到 document.body 下,但逻辑上仍然属于当前组件的生命周期。
4. 常见误区 & 实际项目中的坑
误区1:reactive 解构后丢失响应式
1 | const state = reactive({ count: 0, name: 'foo' }) |
toRefs 把 reactive 对象的每个属性转为 ref。这在从 composable 返回多个响应式值时特别有用——调用方可以解构而不丢失响应式。
误区2:watchEffect 中的异步操作导致依赖追踪不完整
1 | watchEffect(async () => { |
watchEffect 只在同步阶段收集依赖。await 之后的代码已经不在同步执行上下文中了,不会被视为依赖。解法:用 watch 显式指定依赖,或在同步阶段读取所有需要的响应式变量。
坑:ref 在普通对象和数组中不会自动解包
1 | const count = ref(0) |
5. 与相关知识的关联 & 对比
| 对比维度 | Options API (Vue2) | Composition API (Vue3) |
|---|---|---|
| 逻辑组织 | 按选项分割(data/methods/computed) | 按功能聚合(composables) |
| 逻辑复用 | mixin(命名冲突、来源不明) | composables(显式导入、无冲突) |
| Tree-shaking | 不支持 | 支持(按需 import) |
| TypeScript | 弱(this 上下文推断困难) | 强 |
| 学习曲线 | 低 | 中 |
6. 现代最佳实践(2024-2025)
- **新项目一律用
<script setup>**,不使用 options API。 - **优先用
ref而不是reactive**——ref 在赋值时不会丢失响应式,解构用 toRefs。 - 逻辑复用一律用 composables(
useXxx函数),不再使用 mixin。 - 异步依赖优先用 Suspense,避免手动维护 loading 状态。
- 新项目标准技术栈:Vue3 + Vite + TypeScript + Pinia + Vue Router 4。
7. 常见疑问解答
Q:setup 函数中为什么不能访问 this?
A:因为 setup() 在组件实例创建之前执行。此时组件实例还没有被初始化,data、methods、computed 等都还没创建。this 指向的是 undefined(严格模式下)。设计意图是让 setup 与组件的其他选项解耦——你在 setup 中定义的变量和方法不依赖组件的 this 上下文,更容易提取为复用的 composable。
Q:<script setup> 编译后到底变成了什么?
A:它编译为一个 setup() 函数,所有顶层的 import 和变量声明都成为这个函数的局部变量,模板中可以直接使用。不需要 return 语句,编译器会自动处理。此外 <script setup> 还让编译器能更准确地分析模板中绑定的变量来源——比手写 setup() 函数能多做一些编译优化。
Q:ref 的 .value 自动解包规则到底是什么?
A:三个规则:① 在模板中自动解包——{{ count }} 就是 count.value;② 在 reactive 中自动解包——reactive({ count }) 后 state.count 就是 number;③ 在普通对象和 reactive 数组中不会解包——obj.count 和 arr[0] 都需要 .value。
关联知识点索引
响应式原理.md— ref/reactive 的 Proxy 实现细节组件通信.md— provide/inject 在 Composition API 中的用法模板编译与渲染.md—<script setup>的编译优化原理
Vue3 diff 算法与虚拟 DOM
发表于 分类于 Vue
本文字数: 9.5k 阅读时长 ≈ 9 分钟
【面试速答版】
Q1: “Vue3 的 diff 算法相比 Vue2 有哪些优化?”
两大优化:PatchFlag + Block Tree。Vue3 在编译阶段给每个 VNode 打上 PatchFlag(标记哪些属性是动态的),运行时 patch 只比较带标记的属性,静态节点完全跳过。同时通过 Block Tree 把所有动态节点收集到一个扁平数组中,运行时直接遍历这个数组而不递归整棵 VNode 树。列表 diff 方面,Vue3 用快速 diff(基于最长递增子序列)替代了 Vue2 的双端 diff,预处理时先跳过前缀/后缀的相同节点,然后对中间未知序列用 LIS 计算最少移动次数,性能更优。
Q2: “什么是 Block Tree?它是如何工作的?”
Block Tree 是 Vue3 在 VNode 树之上的一层”动态节点索引”。render 函数执行时,_openBlock() + _createBlock() 把所有带 PatchFlag 的动态节点扁平化收集到 dynamicChildren 数组中。patch 时只遍历 dynamicChildren,跳过整棵静态子树。这样一来,即使组件有 100 个节点,实际只需要比较其中 3-5 个动态节点。
Q3: “v-for 的 key 有什么用?Vue3 中 key 的优化点是什么?”
key 帮助 diff 算法”识别”同一个节点在不同渲染中是否可复用。没有 key 时,列表的 diff 退化为”逐个位置比较”——头部插入新元素会导致后面所有元素被”更新”而非”移动”。有正确的 key 时,Vue3 的快速 diff 通过最长递增子序列计算出最少移动次数。Vue3 中 key 不仅可以用在 v-for 中,也可以用在 <template v-for> 上(Vue2 不支持)。始终使用唯一且稳定的 key(如后端 id),不要用 index。
【深入理解版】
1. 这个知识点要解决什么问题?
当响应式数据变化时,Vue 需要更新真实 DOM。最粗暴的方式是把整个 DOM 树销毁重建——但这样性能极差。diff 算法的目标就是:用最小的 DOM 操作来完成新旧状态的迁移。
Vue2 的 diff 是全量递归——从根节点开始,逐层比较新旧两棵 VNode 树的所有节点。即使 90% 的节点是静态的(从未变化),每次也要全部比较一遍。Vue3 的目标是:只比较那些可能变化的部分。
2. 核心原理/执行过程
2.1 整体 patch 流程
1 | 响应式数据变化 |
2.2 Block Tree 与动态节点收集
Vue3 在 VNode 上增加了两种数据结构:patchFlag 标记动态类型,dynamicChildren 收集动态子节点。
1 | <template> |
编译后的 render 函数(简化):
1 | function render(_ctx, _cache) { |
patch 时:
1 | // dynamicChildren 只有一条:[span(PatchFlag=3)] |
如果这个组件有 100 个节点,其中 95 个是静态的,那么 dynamicChildren 可能只有 5 个节点。diff 只需要比较 5 个节点——这就是 Vue3 比 Vue2 快的原因。
2.3 快速 diff(patchKeyedChildren)
当新旧两个子节点列表都是动态的(如 v-for 列表),Vue3 使用快速 diff 算法。过程:
1 | 旧列表:[a, b, c, d, e] |
结果是:c 和 d 不动,e 移动位置,f 新增。用最少操作完成了列表更新。
为什么最长递增子序列能算出最少移动? 递增序列中的元素说明它们在旧列表和新列表中的相对顺序一致——不需要移动。剩下的元素才需要移动或新增删除。找最长递增子序列 = 找到最多”不用动”的元素。
3. 实际应用场景
场景1:理解 key 的重要性
1 | <!-- ❌ 不推荐:用 index 做 key --> |
当 list 头部插入新元素时,用 index 做 key 会导致所有已有 li 的 key 都变了(索引全部后移),diff 认为它们都是新节点——所有 li 都会重新创建。用唯一 id 时,key 不变,diff 能识别出哪些是已有节点(只需移动位置而不是重建)。
场景2:理解 Block Tree 的效果
1 | <template> |
即使这个模板看起来有很多节点,Vue3 的 Block Tree 确保只有 <p>{{ message }}</p> 被收集到 dynamicChildren 中。静态的 <ul> 列表在整个组件生命周期中都不会被 diff。
4. 常见误区 & 实际项目中的坑
误区1:认为加了一定 key 就一定性能好
key 帮助 diff 准确识别节点,但如果你只有一个静态列表(没有新增/删除/排序),加不加 key 没有区别。另外用随机值作为 key(:key="Math.random()")会导致每次渲染所有节点都被重新创建——性能极差,且会丢失组件状态。
误区2:v-for 中 index 作为 key “也可以”
1 | <!-- 问题:输入框内容错乱 --> |
用 :key="i",在列表头部插入后,原来索引 0 的输入框现在对应了新数据,React 和 Vue 都会认为”这个 DOM 节点还是之前的”——输入框里残留的旧内容不会清除。
坑:不要在 v-for 中创建内联对象作为 props
1 | <Child v-for="item in items" :key="item.id" :config="{ name: item.name }" /> |
每次渲染都会创建新的 { name: item.name } 对象,导致 Child 每次都会收到”新的” props 引用,触发不必要的更新。如果 Child 能稳定复用,建议提取为方法或 computed。
5. 与相关知识的关联 & 对比
| 对比维度 | Vue2 diff | Vue3 diff |
|---|---|---|
| 整体策略 | 全量递归比较 | Block Tree + 动态节点收集 |
| 静态节点 | 每次重新创建并比较 | 静态提升 + 完全跳过 |
| 属性 diff | 全量比较所有属性 | PatchFlag 按需比较 |
| 列表 diff | 双端 diff(4 指针) | 快速 diff(LIS) |
| key 的作用 | sameVnode 判断 | 基本一致 |
6. 现代最佳实践(2024-2025)
- 始终用唯一且稳定的 key(后端 id 或 uuid),不要用 index。
- 避免在 v-for 循环中创建内联对象/函数——每次渲染都创建新引用,导致不必要的更新。
- 如果列表完全静态,不需要加 key,Block Tree 会直接跳过整个列表。
- **大规模静态内容用
v-once**——渲染一次后永不更新。 - 合理拆分组件——组件是独立的 patch 单元,经常变化的部分单独拆分可缩小 diff 范围。
7. 常见疑问解答
Q:Vue3 的快速 diff 和 Vue2 的双端 diff 有什么区别?
A:双端 diff 用 4 个指针(oldStart、oldEnd、newStart、newEnd)两两比较,匹配成功的节点移动到对应位置。快速 diff 先预处理前缀/后缀的相同节点跳过,然后对中间未知序列用 key → index 映射 + 最长递增子序列计算最少移动次数。快速 diff 代码更简洁(Vue3 核心约 100 行,Vue2 约 300 行),且在大多数场景下效率更高。两者理论上都是 O(n) 复杂度,但快速 diff 的常数更小。
Q:Block Tree 中的 dynamicChildren 是扁平的动态节点数组,嵌套组件中的动态节点怎么处理?
A:每个组件实例是一个独立的 patch 单元。父组件的 Block Tree 只收集父组件模板中直接定义的动态节点,不穿透到子组件内部。子组件内部的动态节点由子组件自己的 Block Tree 处理。所以 dynamicChildren 是”当前组件模板这一层”的动态节点,不是整个组件树的。
七、Vapor Mode——无虚拟 DOM 的未来
7.1 什么是 Vapor Mode
Vapor Mode 是 Vue 团队正在开发的一种新的编译策略(非默认,是可选的编译目标)。它的核心思路是:在编译阶段将模板直接编译为原生 DOM 操作,彻底移除虚拟 DOM。
1 | 传统 Vue 3 运行流程: |
7.2 为什么需要 Vapor Mode
虚拟 DOM 虽然有 diff 性能优势,但也有不可忽视的开销:
1 | 虚拟 DOM 的开销: |
Vapor Mode 直接跳过 VNode 创建和 diff 阶段,将模板编译为等价的命令式 DOM 操作:
1 | <!-- 模板 --> |
1 | // Virtual DOM 模式编译产物 |
7.3 Virtual DOM vs Vapor Mode 对比
| 维度 | Virtual DOM 模式 | Vapor Mode |
|---|---|---|
| VNode 创建 | 每次更新都创建 | 无 |
| diff 开销 | 有(即使 Block Tree 也有) | 无 |
| 内存占用 | 高(VNode 对象 + 响应式系统) | 低(仅响应式系统) |
| 首屏渲染 | 需要执行 render + diff | 直接创建 DOM |
| 更新粒度 | 组件级别(组件内比完后应用更新) | 变量级别(精确到具体 DOM 属性) |
| 动态内容 > 静态内容 | 优秀 | 优秀 |
| 静态内容 > 动态内容 | 有浪费(VNode 创建) | 极优(静态内容只执行一次) |
| 缓存友好性 | 低(每次都创建新对象) | 高 |
| bundle 大小 | 完整 Vue 运行时(含 diff 算法) | 小(不含 virtual DOM 相关代码) |
7.4 Vapor Mode 的更新粒度
Vapor Mode 中每个动态绑定被直接编译为响应式副作用:
1 | <template> |
当 msg 变化时,只有 setText(el, ctx.msg) 被执行——不需要 diff,不需要知道其他节点。
7.5 Vapor Mode 的局限性
1 | ├── 不是 "drop-in" 替代 |
7.6 混合模式(Vapor + Virtual DOM)
Vue 团队的计划不是”二选一”,而是两者共存:
1 | ┌─────────────────────────────────────────┐ |
在同一个应用中,大部分组件继续使用 Virtual DOM 模式(兼容性优先),对性能敏感的组件(大列表、频繁更新的图表、动画)使用 Vapor Mode。
7.7 当前状态与启用方式
1 | Vue 3.4:Vapor Mode 进入实验阶段(RFC + 原型实现) |
7.8 面试题
Q1: Vapor Mode 和虚拟 DOM 哪个更快
1 | 不能简单说哪个"更快",取决于场景: |
Q2: Vapor Mode 会替代虚拟 DOM 吗
1 | 不会完全替代。Vapor Mode 和 Virtual DOM 是互补关系: |
Q3: Vapor Mode 对现有项目的影响
1 | 对现有项目基本无影响——Vapor Mode 是一个可选的编译目标, |
关联知识点索引
模板编译与渲染.md— PatchFlag、Block Tree 的编译过程响应式原理.md— 响应式变化如何触发 patch- Vue 官方 Vapor Mode RFC
Vue3 响应式原理
发表于 分类于 Vue
本文字数: 6.6k 阅读时长 ≈ 6 分钟
Next.js 详解
发表于 分类于 框架和类库
本文字数: 7.5k 阅读时长 ≈ 7 分钟
Nuxt.js 详解
发表于 分类于 框架和类库
本文字数: 5.6k 阅读时长 ≈ 5 分钟