第 11 卷
3步:
- 解析(Parse):通过正则表达式扫描模板字符串,将其解析为抽象语法树(AST),描述模板
的节点结构、属性、子节点等信息;
- 优化(Optimize):遍历AST,标记静态节点(内容不变的节点)和静态根节点,为后续diff优
化做准备;
- 生成(Generate):遍历优化后的AST,将其转换为JS代码(即render函数),该函数内部通
过 createVNode 创建VNode。
- 第二阶段:VNode创建(执行渲染函数):
组件初始化或数据变化时,会执行编译生成的render函数,通过 createVNode(Vue3)或 h 函数(Vue2)创建VNode对象。创建过程中,会根据节点类型(元素节点、组件节点、文本节点等)
封装对应的VNode属性,如元素节点的 type 为标签名、 props 为标签属性,组件节点的 type 为组件对象等。对于嵌套节点,会递归创建子VNode,形成完整的VNode树。
- 第三阶段:VNode渲染/更新(真实DOM挂载/更新):
- 初次渲染(挂载):通过 patch 函数(Vue3核心更新函数)将VNode树渲染为真实DOM。
patch 函数会根据VNode的 type 创建对应的真实DOM节点,设置节点属性( props),再递归渲染子VNode并挂载到父节点,最终将根VNode对应的真实DOM挂载到页面容器(如
#app)。
- 数据更新(重新渲染):数据变化触发响应式系统,重新执行render函数生成新的VNode树。
patch 函数对比新旧VNode树的差异(diff算法),计算出需要更新的“补丁”(如属性修改、子节点新增/删除),仅将差异部分应用到真实DOM,完成页面更新。
- DIFF算法的原理是什么?它是如何提高性能的?
一、DIFF算法的核心原理
DIFF算法(差异算法)是虚拟DOM的核心,其核心目标是高效对比新旧两棵VNode树的差异,计算出最小更新范围。Vue的DIFF算法遵循“同层级对比”“先序遍历”“key复用”三大核心原则,具体原
理如下:
- 同层级对比,拒绝跨层级遍历:
DIFF算法仅对比新旧VNode树中同一层级的节点,不进行跨层级对比。若某一层级节点类型不匹配(如旧节点是'div',新节点是'p'),则直接销毁该层级及以下的旧VNode,创建新的VNode树并挂
载,避免了复杂的跨层级差异计算,降低算法复杂度(时间复杂度从O(n³)降至O(n))。
- 属性对比:若节点类型相同,对比节点的 props 属性,仅更新变化的属性(如新增/删除
class、修改style等);
- 子节点对比:若节点有子节点,进入子节点对比逻辑(核心难点),通过“key匹配”策略复用
节点,减少销毁/创建操作。
- key复用,优化列表对比:
对于列表类子节点(如 v-for 渲染的节点),通过节点的 key 属性判断是否可复用。key是节点的唯一标识,新旧节点key匹配则说明节点可复用,仅需更新属性和子节点;key不匹配则销毁旧节
点、创建新节点。Vue3进一步优化列表对比,引入“最长递增子序列”算法,减少节点移动操作。
二、DIFF算法提高性能的核心逻辑
- 减少真实DOM操作次数:
DIFF算法的核心价值是“计算最小更新范围”,避免全量重新渲染。通过对比新旧VNode树,仅将差异部分(补丁)应用到真实DOM,而非直接替换整个DOM树,大幅减少了真实DOM的创建、删
除、修改操作,降低了重排/重绘开销。
- 通过优化策略降低对比开销:
- 同层级对比简化算法逻辑,将时间复杂度从O(n³)(全量对比)降至O(n)(线性对比),提升对
比效率;
- key复用策略避免了“就地复用”(无key时)导致的节点状态混乱,同时减少了不必要的节点
销毁/创建;
- Vue3新增的PatchFlags优化:编译阶段标记动态节点(如动态文本、动态class),DIFF阶段仅
对比标记的动态部分,忽略静态节点,进一步减少对比开销。
- 批量更新,减少重排/重绘:
DIFF算法计算出的差异会被收集到“更新队列”中,批量应用到真实DOM。批量更新可避免频繁的单个DOM操作触发多次重排/重绘,合并为一次重排/重绘,显著提升性能。
- 虚拟DOM和真实DOM在性能上的对比如何?
虚拟DOM和真实DOM的性能对比需分场景讨论,核心结论是:单次操作真实DOM更快;批量更新/复杂场景下,虚拟DOM通过减少真实DOM操作次数,性能更优。具体对比从3个维度展开:
一、单次操作性能:真实DOM > 虚拟DOM
虚拟DOM是对真实DOM的抽象,其操作本质是JS对象的操作(创建、修改属性等),而真实DOM操作是浏览器引擎的原生操作。但单次操作场景下(如创建一个简单节点并挂载),虚拟DOM需额外执
行“创建VNode→diff对比→应用补丁”三步,而真实DOM可直接调用
VNode+diff+挂载,多一步diff开销)
二、批量更新/复杂场景性能:虚拟DOM > 真实DOM
复杂场景(如列表重排、多属性同时修改、条件渲染组合)或批量更新场景下,真实DOM的性能劣势明显,虚拟DOM的优势凸显:
- 真实DOM的性能瓶颈:每一次真实DOM操作都会触发浏览器重排/重绘,批量操作时会产生大量冗
余的重排/重绘。例如,修改10个列表项的文本,直接操作真实DOM会触发10次重排;若同时修改属性、子节点,重排次数会更多,性能开销极大。
- 虚拟DOM的性能优势:通过diff算法计算出所有需要更新的差异,将批量操作合并为一次真实DOM
更新。例如,修改10个列表项文本,虚拟DOM仅需一次diff对比,然后批量更新10个节点的文本内容,仅触发1次重排,大幅降低开销。
三、长期运行/大型应用性能:虚拟DOM更稳定
大型应用中,页面状态频繁变化(如表单输入、列表筛选、数据分页),真实DOM操作若缺乏统一管理,易出现“重复更新”“无效更新”(如多次修改同一属性)。虚拟DOM通过响应式系统精准触发
更新,配合diff算法过滤无效更新,仅保留必要的真实DOM操作,长期运行性能更稳定。此外,Vue3 的编译优化(静态提升、PatchFlags)进一步优化了虚拟DOM的对比效率,让大型应用的性能优势更
明显。
总结对比表
| 对比场景 | 真实DOM性能 | 虚拟DOM性能 | 优势方 |
|---|---|---|---|
| 单次简单操作(创建/修改单 | 高(无额外对比开销) | 中(需创建VNode+diff) | 真实DOM |
个节点)
| 批量更新(如修改10个节点 | 低(多次重排/重绘) | 高(批量差异更新,一次重 | 虚拟DOM |
|---|---|---|---|
| 属性) | 排) | ||
| 大型应用/频繁状态变化 | 低(易出现无效更新、重复更 | 高(精准更新+编译优化) | 虚拟DOM |
新)
- Vue中key的作用是什么?为什么需要绑定key?
一、key的核心作用
全站分卷索引 · 12 卷
- 1第 1 卷
- Vue 核心知识点深度解析
- 1. Vue3核心源码精读
- • 核心架构:分为响应式系统( reactivity)、编译系统( compiler)、运行时系统
- • 响应式核心:基于 Proxy 实现响应式,源码核心在 @vue/reactivity 包,包含 effect
- • 组件渲染:采用 VNode(虚拟DOM)描述节点,通过 createVNode 创建虚拟节点, patch
- • 组合式API: setup 函数作为入口, ref(原始类型响应式)、 reactive(对象类型响应
- • 编译优化:引入 PatchFlags(补丁标记)和 StaticNode(静态节点),编译阶段标记动态
- 2. Vuex核心源码精读
- • 核心架构:基于单向数据流设计,核心模块包括 Store(核心类,实例化时初始化状态)、
- • 核心原理:
- 3. Pinia核心源码精读
- • 核心原理:
- 2第 2 卷
- 6. Vue中的依赖收集:触发场景与机制
- 一、依赖收集的触发场景
- 二、依赖收集的核心机制
- • 每个响应式对象的每个属性,对应一个 Dep 类(依赖容器),存储该属性对应的 Watcher
- • 采用“靶心-属性-副作用”的映射关系: WeakMap<响应式对象, Map<属性名,
- • 访问属性时,触发 Proxy 的 get 拦截,调用 track 函数,沿上述映射关系,将当前活跃
- 7. Object.defineProperty的缺点 & Vue3选择Proxy的原因
- 一、Object.defineProperty的潜在缺点/限制
- ◦ 该API只能对已存在的属性进行拦截( get / set),无法感知对象新增属性(如
- ◦ Vue2中需通过 Vue.set / this.$set、 Vue.delete / this.$delete 手动触发响应式
- ◦ Vue2中通过重写数组的7个变异方法(push、pop、shift、unshift、splice、sort、reverse)
- ◦ 若要实现对象全属性响应式,需递归遍历对象的所有属性(包括嵌套对象),对每个属性调用
- 3第 3 卷
- ◦ 示例: <input v-model="msg"> 会被编译为 <input :value="msg"
- 二、不同场景的实现细节
- • 表单元素: v-model 根据元素类型自动匹配属性和事件(文本框: value + input;复选
- • 自定义组件: v-model 是 modelValue prop 和 update:modelValue 事件的语法糖,父
- 9. Vue数据变化时视图的更新机制(即时/异步)
- 一、核心原因
- 二、视图更新的具体机制
- ◦ Vue2:基于 Promise.then(微任务)实现异步队列,兼容环境下会降级为 setTimeout
- ◦ Vue3:基于 queuePostFlushCb 函数,优先使用 Promise.then,其次是
- 10. Vue对象/数组的属性变化监听实现原理
- 一、对象属性变化的监听原理
- 二、数组属性变化的监听原理
- 4第 4 卷
- ◦ 当组件首次进入 keep-alive 时,执行组件的创建生命周期( created、 mounted),
- ◦ 当组件被切换(隐藏)时,Vue不会销毁组件实例,而是将其从DOM中移除,组件状态保留在
- ◦ 当组件再次被切换(显示)时,从 cache 中取出对应的组件实例VNode,重新渲染到DOM
- ◦ max:数字,设置缓存上限,当缓存数量超过 max 时,按照LRU策略删除最久未使用的组件
- ◦ 缓存组件新增两个生命周期: activated(组件激活时触发)、 deactivated(组件失
- 三、具体缓存的内容
- 12. $nextTick方法:原理与用途
- 一、 $nextTick的核心原理
- ◦ 兼容处理:若环境不支持Promise,使用 MutationObserver(微任务),再降级为
- 二、 $nextTick的常见用途
- ◦ 示例:
- ◦ 场景:使用 v-if 控制组件显示隐藏,需要在组件显示后执行初始化逻辑(如第三方插件初始
- 5第 5 卷
- • 解决状态混乱问题:在大型应用中,若组件状态分散管理,会导致状态来源不明确、修改不可控、
- • 提升开发效率:统一的状态管理规范,让团队协作更高效,新开发者可快速理解状态的流转逻辑,
- • 增强应用可维护性:状态与组件解耦,当业务逻辑变更时,只需修改Vuex的Action/Mutation,无
- • 支持高级特性:内置支持状态持久化(配合插件)、模块化拆分、命名空间隔离等高级特性,满足
- 14. Vuex与localStorage在状态管理的不同用途和特性对比
- 一、核心特性对比
- 二、不同用途
- 三、最佳实践
- • 两者结合使用:Vuex负责运行时状态管理,localStorage负责状态持久化,例如:
- • 避免滥用:
- 一、本质区别
- 二、Vuex的核心优势
- 6第 6 卷
- 7第 7 卷
- 8第 8 卷
- 9第 9 卷
- 10第 10 卷
- 11第 11 卷
- 12第 12 卷