Skip to content

Vue 面试题

基础题

1. Vue 2 和 Vue 3 的响应式原理有什么区别?基础

参考答案:

Vue 2 使用 Object.defineProperty 遍历对象属性,将其转换为 getter/setter 实现响应式。

局限性:

  • 无法监听对象新增属性和删除属性(需用 Vue.set / Vue.delete)。
  • 无法监听数组索引和 length 变化(对数组方法做了改写)。
  • 初始化时需递归遍历所有属性,性能开销大。

Vue 3 使用 Proxy 代理整个对象:

  • 可监听新增、删除属性。
  • 可监听数组索引和 length 变化。
  • 支持 Map、Set。
  • 初始化无需递归,访问到嵌套对象时才做响应式转换(lazy reactivity)。
const state = reactive({ count: 0 });
state.count++; // 触发依赖更新
state.newKey = 'value'; // 同样可被监听

评分维度

  • 能说出两种实现方式(30%)
  • 能说明 Vue 2 局限(30%)
  • 能说明 Vue 3 优势并举例(40%)

2. 什么是虚拟 DOM?Vue 的 Diff 算法有什么特点?基础

参考答案:

虚拟 DOM 是用 JavaScript 对象描述真实 DOM 结构的技术。状态变化时,框架先比较新旧虚拟 DOM,再最小化更新真实 DOM。

Vue Diff 特点:

  • 同层比较:只比较同一层级节点,不跨层级。
  • 使用 key:通过 key 识别节点身份,实现复用、移动、删除。
  • Vue 2 双端比较:从新旧节点数组两端同时比较,减少移动次数。
  • Vue 3 快速 Diff:引入最长递增子序列(LIS)优化移动节点,静态节点提升、PatchFlag 标记动态节点减少比较范围。

示例:列表中 key 使用稳定 ID,能让 Vue 正确识别元素移动而不是全部销毁重建。

评分维度

  • 能解释虚拟 DOM(30%)
  • 能说明 Diff 特点(40%)
  • 能说明 key 的作用(30%)

3. Composition API 相比 Options API 有什么优势?基础

参考答案:

Composition API 是 Vue 3 引入的新的逻辑组织方式,相比 Options API 有以下优势:

  1. 按逻辑组织代码:同一功能的 data、methods、computed、watch 可写在一起,而不是分散在不同 option 中。
  2. 更好的逻辑复用:通过自定义组合式函数(Composables)抽取可复用逻辑,替代 mixin 的命名冲突和来源不明问题。
  3. 更好的 TypeScript 支持:函数式 API 更利于类型推断和类型安全。
  4. 更灵活的代码组织:没有选项限制,可自由组合响应式 API。
  5. Tree Shaking 友好:只用到的 API 才会被打包。

示例:把获取用户列表的逻辑封装成 useUserList,在多个组件中复用。

// composables/useUserList.js
import { ref, onMounted } from 'vue';

export function useUserList() {
  const users = ref([]);
  const loading = ref(false);

  const fetchUsers = async () => {
    loading.value = true;
    users.value = await api.getUsers();
    loading.value = false;
  };

  onMounted(fetchUsers);

  return { users, loading, fetchUsers };
}

// 组件中使用
const { users, loading } = useUserList();

评分维度

  • 能说出按逻辑组织代码(25%)
  • 能说明复用性提升(25%)
  • 能提到 TS 支持与 Tree Shaking(30%)
  • 能写出 Composable 示例(20%)

4. ref 和 reactive 有什么区别?基础

参考答案:

特性 ref reactive
数据类型 任意类型(推荐基本类型) 对象/数组/Map/Set
访问方式 .value 直接访问属性
重新赋值 可直接替换整个值 替换对象会丢失响应式
解构 不会丢失响应式 解构会丢失响应式
使用场景 基本类型、需要重新赋值的值 复杂对象

示例:

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

const user = reactive({ name: 'Tom' });
user.name = 'Jerry';

注意:reactive 对象解构会丢失响应式,应用 toRefs 转换后再解构。

评分维度

  • 能说出核心区别(40%)
  • 能说明使用场景(30%)
  • 能提醒 reactive 的局限性(30%)

5. Vue Router 的 Hash 模式和 History 模式有什么区别?基础

参考答案:

特性 Hash 模式 History 模式
URL 形式 /#/path /path
服务端配置 不需要 需要配置 fallback 到 index.html
兼容性 更好,兼容旧浏览器 依赖 HTML5 History API
SEO 较差 更好
刷新行为 不会发送 # 后内容到服务端 会向服务端请求当前路径

History 模式需要 Nginx/服务器配置:

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

选择:对 SEO 和 URL 美观有要求用 History;需要零服务端配置或兼容旧环境用 Hash。

评分维度

  • 能区分两种模式(40%)
  • 能说明服务器配置差异(30%)
  • 能给出选型建议(30%)

进阶题

6. Vue 3 的响应式系统是如何实现依赖收集的?进阶

参考答案:

Vue 3 响应式系统基于 Proxy + effect + dep

  1. 依赖收集(track):当响应式对象属性被读取时,如果当前有活跃的 effect,则将该 effect 收集到该属性对应的 dep 中。
  2. 触发更新(trigger):当属性被修改时,dep 通知所有收集到的 effect 重新执行。
  3. effect 管理effect 函数执行时会把自己设为全局活跃 effect,执行完清除。
const state = reactive({ count: 0 });
effect(() => {
  console.log(state.count); // track
});
state.count++; // trigger,重新执行 effect

依赖存储结构:WeakMap<Target, Map<Key, Set<Effect>>>,使用 WeakMap 避免内存泄漏。

评分维度

  • 能解释 effect 和 dep(30%)
  • 能说明 get 时收集依赖(30%)
  • 能说明 set 时触发更新并提到 WeakMap(40%)

7. Vue 的计算属性和方法有什么区别?进阶

参考答案:

特性 computed methods
缓存 基于依赖缓存 每次调用都执行
适用场景 依赖稳定、计算较复杂 事件处理、需要参数
性能 依赖不变时无重复计算 重复执行
写法 像属性一样访问 函数调用

示例:

const fullName = computed(() => firstName.value + ' ' + lastName.value);

function greet() {
  return 'Hello ' + fullName.value;
}

在模板中频繁使用且依赖不变时,优先用 computed;需要传参或响应事件用 methods。

评分维度

  • 能说明缓存特性(40%)
  • 能说明使用场景(30%)
  • 能举例说明(30%)

8. Vue 的 nextTick 是什么?进阶

参考答案:

nextTick 用于在下次 DOM 更新循环结束后执行回调。Vue 的 DOM 更新是异步的,修改响应式数据后不会立即更新真实 DOM。

示例:

import { nextTick } from 'vue';

const count = ref(0);
async function increment() {
  count.value++;
  console.log(document.getElementById('num').textContent); // 可能还是旧值
  await nextTick();
  console.log(document.getElementById('num').textContent); // 已更新
}

原理:Vue 将同一事件循环中的状态变更缓冲,在微任务阶段统一更新 DOM,nextTick 就是把回调放到这个微任务之后。

评分维度

  • 能解释 nextTick 作用(30%)
  • 能说明异步更新机制(40%)
  • 能写出使用方式(30%)

9. Pinia 相比 Vuex 有什么改进?进阶

参考答案:

Pinia 是 Vue 官方推荐的新一代状态管理库,相比 Vuex 4 的改进:

  1. API 更简洁:没有 mutations,直接修改 state。
  2. 更好的 TypeScript 支持:类型推断更自然,无需复杂模块声明。
  3. Composition API 风格:与 Vue 3 更契合。
  4. 模块化更简单:每个 store 是独立模块,无需嵌套命名空间。
  5. 体积更小:核心代码更少。
  6. 支持 SSR:与 Nuxt 3 深度集成。
  7. Devtools 支持:提供时间旅行、状态检查等能力。

示例:

export const useUserStore = defineStore('user', {
  state: () => ({ name: 'Tom' }),
  getters: { upperName: (state) => state.name.toUpperCase() },
  actions: { updateName(name) { this.name = name; } }
});

评分维度

  • 能说出 4 个以上改进(40%)
  • 能说明 mutations 变化(30%)
  • 能提到 TS 支持(30%)

10. Vue 的 v-if 和 v-show 有什么区别?进阶

参考答案:

特性 v-if v-show
渲染行为 条件为 false 时不渲染元素 始终渲染,通过 display: none 控制显示
切换开销 高(创建/销毁组件) 低(仅 CSS 切换)
初始渲染开销 可能更低(条件为 false 时不渲染) 更高(无论如何都渲染)
适用场景 不频繁切换 频繁切换

注意:

  • v-if 是“真正的”条件渲染,会触发组件生命周期。
  • v-show 只是视觉隐藏,组件状态保留。

评分维度

  • 能区分渲染行为(40%)
  • 能说明开销差异(30%)
  • 能给出使用建议(30%)

高级题

11. Vue 3 的编译优化有哪些?深入

参考答案:

Vue 3 编译器进行了大量优化:

  1. 静态节点提升(hoistStatic):把不依赖状态的节点提升到渲染函数外部,避免每次渲染重新创建。
  2. 静态属性提升:静态 class、style 等属性同样提升。
  3. PatchFlag 标记动态节点:编译时标记哪些节点是动态的,Diff 时只比较动态部分。
  4. Block Tree:把整个模板划分为 Block,只追踪动态子节点,减少遍历范围。
  5. 事件监听缓存(cacheHandlers):内联事件函数缓存,避免子组件不必要的更新。
  6. SVG 优化:对 SVG 内容进行静态提升和更精确的更新。

这些优化让 Vue 3 在大型、复杂模板下性能显著提升。对比 Vue 2 的全量 Diff,Vue 3 编译时会标记动态节点,渲染时只对比动态部分。

<!-- 编译后:只有 msg 会被标记为动态节点 -->
<template>
  <div>
    <h1>Static Title</h1>
    <p>&#123;&#123; msg &#125;&#125;</p>
  </div>
</template>

评分维度

  • 能说出 3 个以上优化(35%)
  • 能解释静态节点提升(25%)
  • 能说明 PatchFlag 作用(25%)
  • 能对比 Vue 2 全量 Diff(15%)

12. 如何设计一个大型 Vue 应用?深入

参考答案:

大型 Vue 应用设计要点:

  1. 技术栈:Vue 3 + TypeScript + Vite,使用 <script setup> 和 Composition API。
  2. 状态管理:Pinia 管理全局状态,局部状态优先使用 ref/reactive。
  3. 路由:Vue Router 4,按功能模块拆分路由配置,使用路由懒加载。
  4. 代码组织:按业务领域(features)划分目录,避免按类型平铺。
  5. 组件分层:基础组件(UI)+ 业务组件 + 页面组件。
  6. 逻辑复用:把公共逻辑封装为 Composables。
  7. 请求层:封装统一的 Axios/fetch 请求层,处理错误、鉴权、缓存。
  8. 工程化:ESLint、Prettier、单元测试、E2E、CI/CD。
  9. 可观测性:错误监控、性能监控、埋点。

评分维度

  • 能说出 5 个以上设计点(40%)
  • 能说明代码组织方式(30%)
  • 能说明状态管理与工程化(30%)

13. Vue 的响应式系统有什么局限?深入

参考答案:

Vue 3 响应式系统虽然比 Vue 2 强大,但仍有局限:

  1. reactive 不能直接替换整个对象user = newObj 会丢失响应式,应修改属性或使用 ref。
  2. reactive 对象解构会丢失响应式:需用 toRefs 转换。
  3. ref 需要 .value:在 JS 中访问略显繁琐。
  4. 对原始值有限制:Proxy 只能代理对象,基本类型必须用 ref 包装。
  5. 某些内置对象需特殊处理:如 Date、自定义类可能需要额外处理。
  6. 大型对象性能:深层嵌套对象首次访问时仍有响应式转换开销。

最佳实践:基本类型和需要重新赋值的用 ref;复杂对象用 reactive 但避免替换和解构。

评分维度

  • 能说出 3 个以上局限(40%)
  • 能说明解构问题(30%)
  • 能给出解决方案(30%)

14. Vue 的 Teleport 有什么作用?深入

参考答案:

Teleport 允许把组件的一部分模板渲染到 DOM 中的其他位置,类似 React Portal。常用于模态框、Toast、Tooltip 等需要脱离父组件布局上下文的场景。

示例:

<Teleport to="body">
  <div class="modal">Modal Content</div>
</Teleport>

特点:

  • 逻辑上仍属于当前组件,props、事件、生命周期正常。
  • 渲染目标 DOM 节点需在挂载时存在。
  • 可用于解决 z-indexoverflow: hidden 等层叠上下文问题。

评分维度

  • 能解释 Teleport(40%)
  • 能说明使用场景(30%)
  • 能写出基本用法(30%)

15. Vue 应用性能优化有哪些手段?深入

参考答案:

Vue 性能优化应从渲染、加载、运行时多个层面入手:

  1. 减少不必要渲染:使用 computedv-oncev-memo、合理拆分组件。
  2. 异步组件defineAsyncComponent 实现路由/弹窗懒加载。
  3. 虚拟列表:长列表使用 vue-virtual-scroller 等库。
  4. keep-alive:缓存不常销毁的组件状态。
  5. 合理使用 key:列表使用稳定 ID,避免索引 key。
  6. 避免过度响应式:大数据、临时对象避免转为响应式。
  7. 路由懒加载component: () => import('./Page.vue')
  8. 构建优化:Tree Shaking、Gzip/Brotli、CDN、图片压缩。
  9. 使用 Profiler:Vue DevTools 定位性能瓶颈。

评分维度

  • 能说出 4 种以上方法(40%)
  • 能解释原理(30%)
  • 能结合实际选择(30%)

补充题

16. Vue 的 Provide/Inject 是什么?基础

参考答案:

Provide/Inject 用于祖先组件向后代组件传递数据,避免 props 层层传递。

示例:

// 祖先
const theme = ref('dark');
provide('theme', theme);

// 后代
const theme = inject('theme');

注意:

  • 适合低频更新的全局数据,如主题、语言、用户信息。
  • 默认不是响应式,注入 ref/reactive 后才能响应。
  • 2.x 中 Provide/Inject 不是响应式的;3.x 中配合响应式 API 使用。

评分维度

  • 能解释概念(40%)
  • 能说明使用场景(30%)
  • 能写出基本示例并提到响应式(30%)

17. Vue 的自定义指令如何编写?基础

参考答案:

自定义指令用于直接操作 DOM,适合聚焦、权限、水印等场景。

示例:

const vFocus = {
  mounted: (el) => el.focus()
};

// 使用
<input v-focus />

Vue 3 指令钩子:

  • created:绑定元素属性前。
  • beforeMount:元素挂载前。
  • mounted:元素挂载后(最常用)。
  • beforeUpdateupdated:组件更新前后。
  • beforeUnmountunmounted:卸载前后。

评分维度

  • 能说出指令钩子(40%)
  • 能写出示例(30%)
  • 能说明适用场景(30%)

18. Vue 的 Suspense 是什么?基础

参考答案:

Suspense 用于处理异步依赖,在异步组件或异步 setup 完成前显示 fallback 内容。

示例:

<Suspense>
  <template #default>
    <AsyncComponent />
  </template>
  <template #fallback>
    <Loading />
  </template>
</Suspense>

特点:

  • 可与异步组件 <AsyncComponent> 配合使用。
  • Vue 3 中 Suspense 是实验性特性,但已在实际项目中广泛使用。
  • 提供了声明式的加载状态管理,替代手动 v-if 控制 loading。

评分维度

  • 能解释概念(40%)
  • 能说明与异步组件配合(30%)
  • 能写出基本用法(30%)

19. Vue 与 React 有什么主要区别?基础

参考答案:

维度 Vue React
定位 渐进式框架 视图库
模板 模板语法(HTML-like) JSX
响应式 自动追踪依赖 手动 setState / useState
状态管理 官方 Pinia / Vuex Redux / Zustand / Jotai 等第三方
路由 官方 Vue Router React Router 第三方
学习曲线 相对平缓 相对陡峭

共同点:

  • 都基于组件化、虚拟 DOM、单向数据流。
  • 都支持 Hooks / Composition API 风格的逻辑复用。
  • 都有庞大的生态和社区。

选择:Vue 适合快速上手、模板清晰的项目;React 适合高度灵活、生态丰富的项目。

评分维度

  • 能说出 3 个以上区别(40%)
  • 能客观评价(30%)
  • 能说明共同点(30%)

20. 你如何看待 Vue 3 的替代 Vue 2?基础

参考答案:

Vue 3 在性能、TypeScript 支持、Composition API、Tree Shaking 等方面有显著提升,是Vue 生态的未来方向。

建议:

  • 新项目:优先使用 Vue 3 + Vite + TypeScript + <script setup>
  • 存量 Vue 2 项目:评估迁移成本,可采用渐进式迁移或官方迁移构建(Vue 2.7 提供了部分 Composition API)。
  • 团队学习:重点掌握 Composition API、响应式原理、新生命周期和 Pinia。

不应盲目迁移,应结合业务需求、技术债和团队能力做决策。

评分维度

  • 能说明 Vue 3 优势(40%)
  • 能说明迁移考虑(30%)
  • 能给出建议(30%)

21. Vue 3.4 有哪些值得关注的新特性?基础

参考答案:

Vue 3.4 主要新特性:

  1. defineModel:简化 v-model 实现,无需手动声明 props 和 emits。
  2. v-bind 同名简写<Child :title :user /> 等价于 <Child :title="title" :user="user" />
  3. 响应式系统优化:computed 更高效,watchEffect 清理逻辑更可靠。
  4. 类型推断改进:减少 TypeScript 类型错误和 any

示例:

<script setup>
const modelValue = defineModel();
</script>

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

评分维度

  • 能说出 3 个以上新特性(40%)。
  • 能解释 defineModel 用法(30%)。
  • 能说明 v-bind 同名简写(30%)。

22. 什么是 Vapor Mode?它解决了什么问题?基础

参考答案:

Vapor Mode 是 Vue 正在开发的全新编译策略,放弃虚拟 DOM,编译为更细粒度的 DOM 操作指令。

优势:

  • 更小的包体积。
  • 更低的内存占用。
  • 更快的更新性能(特定场景)。

特点:

  • 不需要修改业务代码。
  • 通过编译器选项开启(实验阶段)。
  • 将进一步缩小 Vue 与 Svelte 等无虚拟 DOM 方案的差距。

评分维度

  • 能解释 Vapor Mode 概念(30%)。
  • 能说明与传统虚拟 DOM 的区别(30%)。
  • 能说出优势和当前状态(40%)。

23. 什么是 Vue Router Data Loaders?它解决了什么问题?基础

参考答案:

Vue Router Data Loaders 是路由级数据加载方案,让数据获取逻辑从组件中分离出来。

示例:

import { defineLoader } from "vue-router";

export const useUserData = defineLoader(async (route) => {
  const res = await fetch(`/api/users/${route.params.id}`);
  if (!res.ok) throw new Error("User not found");
  return res.json();
});

组件中使用:

<script setup>
const { data, error, isLoading } = useUserData();
</script>

解决问题:

  • 数据加载逻辑分散。
  • 导航等待体验难以统一。
  • SSR 数据预取困难。

评分维度

  • 能解释 Data Loaders 概念(30%)。
  • 能写出 defineLoader 示例(40%)。
  • 能说明解决的问题(30%)。

领域编号:E07 Vue
最后更新:2026-06-24

基于 MIT 协议发布