技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTVUE

Vue 20+ 面试题整理:Vue 2.7 与 Vue 3.5 现代答案

所属馆藏
Vue
文件格式
Markdown
原始路径
Vue/53-「面试题」20+Vue面试题整理
本文目录26 个章节
  1. 0. 你能讲一讲 MVVM 吗?
  2. 1. 简单说一下 Vue 2.x 的响应式数据原理
  3. 2. Vue 3.x 的响应式数据原理是什么?
  4. 3. Vue 2 如何监测数组变化?
  5. 4. nextTick 知道吗?实现原理是什么?
  6. 5. 说一下 Vue 的生命周期
  7. 6. 接口请求一般放在哪个生命周期?
  8. 7. computed 和 watch 有什么区别?
  9. 8. v-if 和 v-show 的区别
  10. 9. 组件中的 data 为什么是函数?
  11. 10. v-model 的原理是什么?
  12. 11. Vue 事件绑定原理是什么?
  13. 12. 模板编译原理是什么?
  14. 13. Vue 2 和 Vue 3 的 diff 算法分别怎样?
  15. 14. 虚拟 DOM 和 key 的作用是什么?
  16. 15. KeepAlive 了解吗?
  17. 16. Vue 组件生命周期调用顺序
  18. 17. Vue 2/3 组件通信有哪些方式?
  19. 18. SSR 了解吗?
  20. 19. 做过哪些 Vue 性能优化?
  21. 20. hash 路由和 history 路由的实现原理
  22. 21. 动态组件和异步组件有什么区别?
  23. 22. 为什么不建议 v-if 和 v-for 写在同一元素?
  24. 23. 如何回答得更准确
  25. 官方参考
  26. 原文出处

Vue 20+ 面试题整理:Vue 2.7 与 Vue 3.5 现代答案

原文以面试对话形式整理了 20 个 Vue 问题,很多基础结论仍然有价值,但部分答案停留在 Vue 2、Vue Router 3 和旧版 Lighthouse。本文保留原文题目顺序和面试风格,同时给出 Vue 2.7.16、Vue 3.5.39 的版本边界。

Vue 2.7 是 Vue 2 的最终 minor 版本,Vue 2 官方维护已于 2023 年 12 月 31 日结束;面试和维护旧项目仍需要理解 Vue 2,但新项目应优先选择 Vue 3。

0. 你能讲一讲 MVVM 吗?

MVVM 是 Model-View-ViewModel 的缩写:

  • Model:业务数据和状态;
  • View:用户看到的 UI;
  • ViewModel:连接状态和视图的层,负责响应式更新、事件和视图状态转换。

Vue 可以用 MVVM 解释,但不要把 Vue 的所有实现都强行等同于经典 MVVM。Vue 组件更强调:

响应式状态 ──> 模板/渲染函数 ──> DOM
    ▲                              │
    └────── 事件、emit、action ────┘

Vue 的 props 默认是单向下行,子组件通过 emit 通知父组件;v-model 只是把 prop 和事件组合成方便的双向编辑协议。复杂应用还会使用 Pinia/store 管理跨组件状态。

1. 简单说一下 Vue 2.x 的响应式数据原理

Vue 2.7.16 初始化 data 时,会递归遍历对象属性,用 Object.defineProperty 定义 getter/setter:

读取属性
  ↓
getter 收集当前渲染 Watcher 到 Dep

修改属性
  ↓
setter 调用 Dep.notify()
  ↓
Watcher 进入更新队列
  ↓
批量执行组件重新渲染或 watch 回调

Vue 2 还会改写数组的 pushpopshiftunshiftsplicesortreverse 方法,以便在这些变异操作后通知依赖。

限制:

// Vue 2 不能直接侦测新增属性
this.user.age = 18

// Vue 2 不能直接侦测数组索引赋值和 length 改变
this.items[2] = 'new'
this.items.length = 0

应该使用:

this.$set(this.user, 'age', 18)
this.$set(this.items, 2, 'new')
this.items.splice(0, this.items.length)

Vue 2.7 仍然是 getter/setter 实现。它回移植了 Composition API 和 <script setup>,不代表它获得了 Vue 3 的 Proxy 响应式。

2. Vue 3.x 的响应式数据原理是什么?

Vue 3 使用 Proxy 代理对象,使用 ref 包装基本类型:

import { reactive, ref } from 'vue'

const state = reactive({ count: 0 })
state.count++

const count = ref(0)
count.value++

可以抽象为:

WeakMap<原始对象, Map<属性, Dep>>

读取时 track(target, key) 收集当前 effect,写入时 trigger(target, key) 找到相关 effect 并调度执行。reactive 对嵌套对象也提供深层响应式代理,但转换通常在访问时发生。

原文说 Proxy“有 13 种拦截方法”并不是回答重点;Proxy 能拦截多种对象操作,真正重要的是 Vue 如何把这些操作映射到依赖收集和触发更新。

Vue 3.5.39 内部已经使用 DepLink、Subscriber 和版本号等机制优化依赖关系,网上基于简单 WeakMap<target, Map<key, Set<effect>>> 的代码适合作为原理伪代码,不应当标成当前源码逐行实现。

Vue 2.7 与 Vue 3 的一个差异:

// Vue 2.7:回移植 reactive 会直接转换原对象
reactive(object) === object // true

// Vue 3:返回 Proxy
reactive(object) === object // false

3. Vue 2 如何监测数组变化?

Vue 2 无法通过 Object.defineProperty 直接拦截数组索引和 length,因此会:

  1. 让数组继承一个改写后的原型;
  2. 包装七个变异方法;
  3. 方法执行原生操作后观察新插入的对象;
  4. 通知数组 Dep;
  5. 重新执行相关 watcher。
const methods = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse',
]

推荐:

this.items.push(item)
this.items.splice(index, 1, nextItem)
this.$set(this.items, index, nextItem)

Vue 3 的 Proxy 可以追踪数组索引、length 和数组方法产生的相关操作,但批量更新和大数组渲染成本仍然存在。Proxy 解决的是“能否观察到”,不是“渲染一百万个 DOM 很快”。

4. nextTick 知道吗?实现原理是什么?

Vue 的响应式状态修改后,DOM 更新通常不是同步完成的。Vue 会把更新任务放进队列,合并同一批修改,再在后续 microtask/更新阶段刷新。

import { nextTick, ref } from 'vue'

const count = ref(0)

async function increment() {
  count.value++
  console.log(document.querySelector('#count')?.textContent)
  // 可能仍是旧 DOM

  await nextTick()
  console.log(document.querySelector('#count')?.textContent)
  // 本次更新后的 DOM
}

Vue 2 的 nextTick 会根据环境尝试 Promise、MutationObserver、setImmediate,最后使用 setTimeout;Vue 3 的调度器主要使用 Promise 微任务。公共语义是等待当前 Vue 更新批次完成,不是保证“固定等待 0ms”。

注意:

  • nextTick 只等待 Vue 已安排的 DOM 更新;
  • 它不等待接口请求、图片下载或 CSS 动画完成;
  • 需要等待图片尺寸时使用 img.decode() 或加载事件;
  • 需要等待路由组件加载时使用路由/异步组件提供的状态,而不是猜一个 setTimeout。

5. 说一下 Vue 的生命周期

Vue 2.7

beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
beforeDestroy
destroyed

Vue 3.5

setup / onBeforeMount
onMounted
onBeforeUpdate
onUpdated
onBeforeUnmount
onUnmounted

Vue 3 的生命周期组合式 API:

<script setup lang="ts">
import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
} from 'vue'

onBeforeMount(() => {})
onMounted(() => {})
onBeforeUpdate(() => {})
onUpdated(() => {})
onBeforeUnmount(() => {})
onUnmounted(() => {})
</script>

几个常见边界:

  • created/setup 可以访问响应式状态,但不能依赖已挂载 DOM;
  • mounted/onMounted 适合 DOM、浏览器 API 和 $refs
  • SSR 不执行 mounted、updated、unmounted 等客户端 DOM 钩子;
  • KeepAlive 切换时进入 activated/deactivated,而不一定创建和销毁实例;
  • Vue 3 将 beforeDestroy/destroyed 改名为 beforeUnmount/unmounted

原文说在 beforeUpdate 中修改数据“不会造成重渲染”过于绝对。更新钩子中再次修改相关状态可能造成额外更新甚至循环,应该避免在 updated 中无条件写入响应式状态。

6. 接口请求一般放在哪个生命周期?

没有“所有请求都放 mounted”的固定答案:

  • 不依赖 DOM 的初始数据:可以在 Vue 2 created、Vue 3 setup,或路由数据加载阶段请求;
  • 需要 DOM/浏览器 API:放在 mounted/onMounted
  • Nuxt SSR:使用 useAsyncDatauseFetchserverPrefetch 等适合 SSR 的数据获取方式;
  • KeepAlive 组件重新激活需要刷新:使用 activated/onActivated,并防止重复请求;
  • 参数变化:使用 beforeRouteUpdateonBeforeRouteUpdate 或 watch route;
  • 组件卸载或参数变化:使用 AbortController/请求库取消旧请求,避免旧响应覆盖新状态。
import { onBeforeUnmount, ref } from 'vue'

const data = ref(null)
const controller = new AbortController()

fetch('/api/data', { signal: controller.signal })
  .then(response => response.json())
  .then(value => {
    data.value = value
  })
  .catch(error => {
    if (error.name !== 'AbortError') throw error
  })

onBeforeUnmount(() => {
  controller.abort()
})

7. computed 和 watch 有什么区别?

computed

computed 用于根据响应式状态得到同步派生值:

const activeTodos = computed(() => {
  return todos.value.filter(todo => !todo.done)
})

它具有缓存:依赖不变时重复读取不会重新执行 getter。getter 应尽量是纯函数,不负责请求、日志或修改其他状态。

Vue 2 的 computed 主要是 lazy Watcher、dirtyevaluatedepend;Vue 3.5.39 的 ComputedRefImpl 直接作为响应式订阅者,结合 Dep/Link、版本号和 refreshComputed 工作,不能继续把它概括成“computed 就是一个 ReactiveEffect”。

watch

watch 监听明确的数据源,适合副作用:

watch(
  () => route.params.id,
  async id => {
    await loadUser(String(id))
  },
  { immediate: true },
)

Vue 3 支持:

  • ref;
  • getter;
  • reactive 对象;
  • 多个 source 数组;
  • immediatedeeponceflush
  • Vue 3.5 的 deep: number 有限深度;
  • onWatcherCleanup 或回调第三参数取消过期异步任务。
watchEffect(async () => {
  const response = await fetch(`/api/${id.value}`)
  result.value = await response.json()
})

watchEffect 自动追踪 effect 中同步访问的依赖;异步回调中第一个 await 之后新访问的依赖不会被同样方式追踪。需要明确 source、新旧值或精确控制时使用 watch

8. v-ifv-show 的区别

<Panel v-if="visible" />
<Panel v-show="visible" />
  • v-if 条件为假时不创建/挂载 DOM 和组件,切换会创建或卸载;
  • v-show 初次就创建,通过 display 切换;
  • 低频切换或初始不需要的昂贵内容适合 v-if
  • 高频切换且希望保留状态时考虑 v-show
  • 需要保留组件实例但切换路由时考虑 KeepAlive。

“更多情况下使用 v-if”不是绝对结论,应按切换频率、初始化成本、内存和状态保留需求选择。

9. 组件中的 data 为什么是函数?

在 Vue 2 组件中,data 应该是返回对象的函数:

export default {
  data() {
    return {
      count: 0,
    }
  },
}

每次创建组件实例时调用函数,可以得到独立的数据对象;如果多个实例共享同一个对象,就会相互污染。

const shared = { count: 0 }

// 不要把同一个可变对象直接作为组件 data
export default {
  data: () => shared,
}

Vue 3 Composition API 中,状态通常在 setup 内创建,每个组件实例会执行自己的 setup:

<script setup>
import { ref } from 'vue'

const count = ref(0)
</script>

组件工厂仍应避免把可变的模块级对象当作所有实例共享状态,除非这就是有意设计的全局状态。

10. v-model 的原理是什么?

原生文本输入框:

<input v-model="text" />

可近似看成:

<input
  :value="text"
  @input="text = $event.target.value"
/>

不同输入类型会使用不同 property/event。组件协议则按版本不同:

Vue 2:value + input
Vue 3:modelValue + update:modelValue
Vue 3.4+:defineModel() 宏简化上述协议

Vue 2:

<LegacyInput v-model="title" />

约等于 :value="title" @input="title = $event"

Vue 3:

<ModernInput v-model="title" />

约等于 :modelValue="title" @update:modelValue="title = $event"

Vue 3.5 新代码可以:

<script setup>
const model = defineModel()
</script>

<template>
  <input v-model="model" />
</template>

11. Vue 事件绑定原理是什么?

原生 DOM 事件最终会通过 addEventListener 等方式绑定到元素;Vue 会在 patch 阶段更新事件 invoker,使模板中的事件处理器与真实 DOM 监听器保持同步。

<button @click="save">保存</button>

组件事件不是浏览器事件:

<Child @save="handleSave" />

子组件需要显式:

emit('save', payload)

Vue 2 组件实例有 $on/$off/$once,Vue 3 已移除这些实例事件 API。Vue 3 应使用 defineEmits、Pinia、provide/inject 或独立事件库,不要把 $on 代码直接迁移到 Vue 3。

事件修饰符会被编译为相应逻辑:

<form @submit.prevent="submit">
  <button @click.stop="save">保存</button>
</form>

.stop 阻止冒泡,.prevent 阻止默认行为,.passive 声明监听器不会调用 preventDefault,三者含义不同。

12. 模板编译原理是什么?

Vue 2

template
  ↓ parse
AST
  ↓ optimize
标记静态节点
  ↓ codegen
render 函数
  ↓
VNode

Vue 2 使用模板解析器、优化器和代码生成器。静态节点可以跳过部分更新比较;生产项目通常在构建阶段编译模板,运行时构建才包含编译器。

Vue 3

Vue 3 仍然生成渲染函数和 VNode,但编译器会提供更丰富的运行时提示:

  • 静态节点提升;
  • patch flags;
  • block tree;
  • 动态后代收集;
  • SSR hydration 快路径。
<div class="static">固定内容</div>
<div :class="className">{{ message }}</div>

运行时可以根据 patch flag 只更新 class 或 text,而不是完整比较所有属性。Vue 3 的性能提升不是“只靠位运算”,而是编译器、渲染器和响应式系统共同作用。

13. Vue 2 和 Vue 3 的 diff 算法分别怎样?

两代 Vue 都采用同层级比较的启发式算法,而不是计算任意两棵树的最优编辑距离。完整通用树 diff 的理论复杂度很高,Vue 通过以下假设换取实际性能:

  • 只比较同层级节点;
  • 通过节点类型判断能否复用;
  • 使用 key 建立新旧子节点的对应关系;
  • 不主动处理跨层级节点移动。

Vue 2

Vue 2 的核心 children diff 使用双端比较:

旧头 ↔ 新头
旧尾 ↔ 新尾
旧头 ↔ 新尾
旧尾 ↔ 新头

命中后移动或复用节点,必要时再通过 key 建立索引。没有稳定 key 时,输入框状态和组件实例可能被错误复用。

Vue 3

Vue 3 使用 patch flags、block tree 和更细的 renderer fast path;对 keyed children 的未知序列,会计算最长递增子序列(LIS)以减少移动。它借鉴过 ivi、Inferno 等实现思想,但不要简化为“Vue 3 完全使用某个外部库”。

“Vue diff 一定是 O(n)”也不应当当作数学定理。它是在类型、同层级、keyed children 和编译器提示等假设下的工程优化;复杂业务、动态 key 和大组件更新仍可能昂贵。

14. 虚拟 DOM 和 key 的作用是什么?

VNode 是描述节点类型、props、children 和组件信息的 JavaScript 数据结构。Vue 通过 renderer 把 VNode 映射到真实 DOM,并在新旧 VNode 之间 patch。

虚拟 DOM 的价值不只是“DOM 很昂贵”:

  • 它让渲染逻辑可声明式表达;
  • 可以批量调度更新;
  • 可以在不同 renderer/SSR 环境复用部分抽象;
  • 编译器可以为运行时提供 patch flags;
  • 但创建 VNode 和运行 diff 也有成本,静态 HTML、直接 DOM 或 canvas 在某些场景可能更合适。

key

<li v-for="todo in todos" :key="todo.id">
  {{ todo.title }}
</li>

key 是同层级节点的稳定身份标识,帮助 Vue 找到可复用的旧节点。不要使用随机 key;列表顺序会变化时也不要无条件使用 index。key 不能解决所有性能问题,也不会让组件自动缓存。

15. KeepAlive 了解吗?

KeepAlive 缓存组件实例:

<KeepAlive :include="['HomeView', 'UserView']" :max="10">
  <component :is="currentView" />
</KeepAlive>

核心点:

  • 切换出去通常触发 deactivated,而不是 unmounted;
  • 切换回来触发 activated,而不是重新 created/mounted;
  • include/exclude 按组件名称匹配;
  • max 超限时按 LRU 思路淘汰缓存;
  • 被淘汰或父级卸载时才真正 unmount/destroy;
  • Vue Router 4 推荐用 router-view 插槽包住真实 Component。
<router-view v-slot="{ Component }">
  <KeepAlive>
    <component :is="Component" />
  </KeepAlive>
</router-view>

它不是“复用 DOM 后完全没有 diff”,而是缓存组件实例并由 renderer 处理激活/停用,过多缓存会增加内存。

16. Vue 组件生命周期调用顺序

普通首次挂载时,宏观顺序是:

父 beforeCreate
父 created
父 beforeMount
  子 beforeCreate
  子 created
  子 beforeMount
  子 mounted
父 mounted

更新时通常是:

父 beforeUpdate
  子 beforeUpdate
  子 updated
父 updated

销毁/卸载时通常是:

父 beforeDestroy / beforeUnmount
  子 beforeDestroy / beforeUnmount
  子 destroyed / unmounted
父 destroyed / unmounted

注意:异步组件、Suspense、Teleport、KeepAlive、条件渲染和组件复用会改变局部时序。Vue 3 迁移名称:

beforeDestroy -> beforeUnmount
destroyed      -> unmounted

17. Vue 2/3 组件通信有哪些方式?

父子

父 -> 子:props
子 -> 父:emit
双向模型:v-model

Vue 2 的组件 v-model 默认是 value/input,Vue 3 是 modelValue/update:modelValue

祖先后代

  • Vue 2/3 都有 provide/inject;
  • Vue 3 可通过 InjectionKey 提供类型;
  • Vue 3 注入 ref 会保留响应式;
  • 不要把隐式依赖注入当作所有数据传递的替代品。

兄弟和跨页面

  • 提升到共同父组件;
  • 使用 Pinia/store;
  • 使用组合式函数;
  • 路由 params/query/meta 传递导航状态;
  • Vue 2 可用事件总线,Vue 3 已移除实例 $on/$off/$once,新代码不建议用隐式事件总线。

ref

ref 适合聚焦、滚动、打开弹窗等命令式操作;Vue 3 <script setup> 子组件需要 defineExpose 才会暴露指定方法。不要用 $parent$children 作为稳定通信协议。

18. SSR 了解吗?

SSR(Server-Side Rendering)是在服务器生成初始 HTML,再由客户端加载 JavaScript 并 hydration:

请求
  ↓
服务器执行组件/数据逻辑并生成 HTML
  ↓
浏览器先显示 HTML
  ↓
下载 JS
  ↓
客户端 hydration 接管交互

优点:

  • 首屏 HTML 更早可见;
  • 搜索引擎更容易读取内容;
  • 适合内容型和公开页面。

代价:

  • 服务器计算和数据请求增加;
  • hydration 仍需要下载和执行 JS;
  • 代码不能在服务端直接使用 windowdocumentlocalStorage
  • 需要处理服务端和客户端输出一致性;
  • 缓存、部署和错误边界更复杂。

Vue 2 SSR 通常不执行 beforeMount/mounted,常用 beforeCreate/created;Vue 3 SSR 会执行 setup 和适合 SSR 的逻辑,但不会执行 onMounted 等客户端钩子。Nuxt 4 还支持 SSR、预渲染、混合渲染和客户端组件,具体选择取决于页面内容和部署方式。

SSR 不等于 SEO 自动完美,也不等于首屏一定更快;服务器响应、数据请求、HTML 大小和 hydration 成本都要测量。

19. 做过哪些 Vue 性能优化?

编码和渲染

  • 路由和大型功能使用动态 import;
  • 大列表使用分页、服务端筛选或虚拟列表;
  • 列表使用稳定唯一 key;
  • 不在同一元素混用 v-ifv-for
  • 根据切换频率选择 v-if/v-show/KeepAlive;
  • 减少不必要的深层响应式和组件更新;
  • computed 用于同步派生值,watch 用于副作用;
  • 图片设置尺寸,非 LCP 图片再懒加载;
  • 清理定时器、事件监听和过期请求。

构建和网络

  • 生产模式、Tree Shaking 和代码压缩;
  • 分析 bundle,清理重复依赖和无用 polyfill;
  • 使用内容 hash、Brotli/gzip、缓存和 CDN;
  • 只预加载真正关键的资源;
  • SSR/SSG/CSR 按页面目标选择;
  • Nuxt 中同时关注服务器响应和客户端 hydration。

指标和定位

当前 Core Web Vitals 重点是:

  • LCP ≤ 2.5s;
  • INP ≤ 200ms;
  • CLS ≤ 0.1。

同时结合 FCP、TTFB、TBT、Speed Index 和 RUM 数据。不要把固定 Lighthouse 分数、旧版 FID/TTI 或“所有请求都放 CDN”当作普适结论。

20. hash 路由和 history 路由的实现原理

hash

URL 中 # 后面的部分是 hash:

https://example.com/#/users

修改 hash 通常不会向服务器请求新的 HTML,浏览器会触发 hashchange;Vue Router 监听并把 hash 解析为路由位置。优点是服务器通常不需要特殊 fallback;缺点是 URL 包含 #,SEO、服务端路由和部分部署体验不如 history 直观。

history

History 模式使用:

history.pushState(state, '', url)
history.replaceState(state, '', url)
window.addEventListener('popstate', handler)

点击站内链接时,Router 通过 pushState 改变地址并执行客户端导航;浏览器前进后退通过 popstate 通知 Router。

History 模式刷新 /users/1 时,服务器必须把该路径回退到应用入口 HTML,否则可能返回 404。Nginx 示例:

location / {
  try_files $uri $uri/ /index.html;
}

这不是 Vue Router 自己能解决的配置问题。Nuxt 的服务端/静态部署还要根据渲染模式配置对应的路由 fallback。

21. 动态组件和异步组件有什么区别?

动态组件是在几个已知组件之间切换:

<component :is="currentComponent" />

异步组件在需要渲染时才加载组件代码:

import { defineAsyncComponent } from 'vue'

const Editor = defineAsyncComponent(() => import('./Editor.vue'))

Vue 3 可以配置 loading、error、delay、timeout 和 retry;Suspense 可以管理异步依赖的 pending/fallback,但不等于接口请求自动被管理。路由懒加载则推荐:

{
  path: '/editor',
  component: () => import('./views/EditorView.vue'),
}

Vue 2 的异步组件使用 callback factory、Promise factory 或 component/loading/error 配置;Vue 2.7 也提供兼容版 defineAsyncComponent,但底层仍是 Vue 2 机制。

22. 为什么不建议 v-ifv-for 写在同一元素?

版本优先级不同:

  • Vue 2.7:v-for 优先,v-if 可以访问 item,但会对遍历项逐个判断;
  • Vue 3.5:v-if 优先,不能依赖同节点的 item/index

推荐:

<!-- 条件与列表无关:放外层 -->
<ul v-if="showList">
  <li v-for="item in items" :key="item.id">
    {{ item.name }}
  </li>
</ul>
// 条件依赖 item:先 computed 过滤
const visibleItems = computed(() => items.value.filter(item => item.visible))
<li v-for="item in visibleItems" :key="item.id">
  {{ item.name }}
</li>

23. 如何回答得更准确

面试中的 Vue 原理题最好带上版本和边界:

  • “Vue 2 使用 defineProperty,Vue 3 使用 Proxy”,后面补充 Vue 2.7 Composition API 仍是旧响应式;
  • “computed 有缓存”,后面区分 Vue 2 lazy Watcher 和 Vue 3.5 ComputedRefImpl
  • “nextTick 等 DOM 更新”,后面说明它不等待接口和图片;
  • “SSR 首屏快、SEO 好”,后面补充服务器、hydration、缓存和数据请求成本;
  • “KeepAlive 用 LRU”,后面说明它缓存实例、max 淘汰和 activated/deactivated;
  • “diff 是 O(n)”,后面说明这是启发式、同层级、key 和编译器提示下的工程复杂度;
  • “性能优化用 Lighthouse”,后面区分实验室数据、RUM 和当前 Core Web Vitals。

官方参考

Vue

Router、Nuxt 与 Web Vitals

原文出处

作者:童欧巴

来源:稀土掘金

本文保留原文 20+ 面试题、对话结构和知识主线,并补充 Vue 2.7.16、Vue 3.5.39、Vue Router 4、Nuxt 4 与当前 Web Vitals 说明。

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS