Skip to content

Vue3 常见问题与面试题

在本章中,我们将介绍 Vue3 的常见问题和面试题,帮助你更好地理解和掌握 Vue3。

常见问题

1. Vue3 与 Vue2 的主要区别是什么?

  • Composition API:Vue3 引入了 Composition API,允许开发者按功能组织代码,而不是按选项类型
  • 响应式系统:Vue3 使用 Proxy 替代 Object.defineProperty,提供了更高效的响应式系统
  • Fragment:Vue3 支持多个根节点
  • Teleport:允许将组件内容渲染到 DOM 树的其他位置
  • Suspense:支持异步组件的加载状态
  • TypeScript:更好的 TypeScript 支持
  • 性能优化:编译优化、运行时优化,整体性能优于 Vue2

2. ref 和 reactive 的区别是什么?

  • ref

    • 可以用于任何类型的数据,包括基本类型和对象
    • 在 JavaScript 中使用时需要通过 .value 访问和修改
    • 在模板中使用时会自动解包,不需要 .value
    • 适合存储基本类型数据或需要单独传递的对象属性
  • reactive

    • 只能用于对象类型数据
    • 直接访问和修改属性,不需要 .value
    • 会递归地将对象的所有属性变为响应式
    • 适合存储复杂的对象数据

3. setup 函数的执行时机是什么?

setup 函数在组件实例创建之前执行,在 beforeCreate 钩子之前。它的返回值会暴露给模板和其他选项式 API 钩子。

4. watch 和 watchEffect 的区别是什么?

  • watch

    • 需要明确指定要监听的数据源
    • 可以获取新旧值
    • 懒执行,只有当监听的数据源变化时才会执行
    • 可以配置深度监听和立即执行
  • watchEffect

    • 自动追踪依赖的响应式数据
    • 无法获取新旧值
    • 立即执行,然后在依赖变化时重新执行
    • 更简洁,适合处理副作用

5. Vue3 的响应式原理是什么?

Vue3 使用 Proxy 实现响应式系统:

  1. 使用 Proxy 包装目标对象,拦截对象的读取、设置、删除等操作
  2. 当读取属性时,收集依赖(将当前的副作用函数添加到依赖集合中)
  3. 当修改属性时,触发依赖(执行所有收集的副作用函数)
  4. 对于嵌套对象,会递归地创建 Proxy

相比 Vue2 的 Object.defineProperty,Proxy 具有以下优势:

  • 可以监听到对象的添加、删除操作
  • 可以监听到数组的索引和 length 变化
  • 不需要初始化时遍历所有属性
  • 性能更好

6. 组件通信的方式有哪些?

  • props:父组件向子组件传递数据
  • emit:子组件向父组件传递事件
  • provide/inject:祖孙组件之间的通信
  • Pinia:全局状态管理
  • mitt:事件总线,适用于任意组件之间的通信
  • $attrs/$listeners:传递未被声明为 props 的属性和事件

7. 什么是 Teleport?

Teleport 是 Vue3 提供的一个内置组件,允许我们将组件的内容渲染到 DOM 树的其他位置,而不是组件的父级 DOM 中。这在处理模态框、弹出菜单等需要脱离正常 DOM 层次结构的场景时非常有用。

8. 什么是 Suspense?

Suspense 是 Vue3 提供的一个内置组件,用于在等待异步组件加载时显示一个占位内容。它可以与异步组件和 defineAsyncComponent 配合使用,提供更好的用户体验。

9. 如何优化 Vue3 应用的性能?

  • 使用 v-memo:缓存模板片段,避免不必要的重新渲染
  • 使用 shallowRef 和 shallowReactive:对于不需要深度响应的数据,使用浅响应式
  • 使用 computed:缓存计算结果,避免重复计算
  • 使用 watchEffect:自动追踪依赖,避免不必要的监听器
  • 组件拆分:将大型组件拆分为小型、可复用的组件
  • 使用虚拟滚动:对于大型列表,使用虚拟滚动减少 DOM 节点
  • 懒加载:使用 defineAsyncComponent 懒加载组件
  • 优化 CSS:使用 scoped CSS 或 CSS Modules,避免全局样式冲突
  • 减少 prop 传递:对于深层组件,使用 provide/inject 或 Pinia

10. Vue3 如何处理 TypeScript?

Vue3 对 TypeScript 提供了更好的支持:

  • 内置 TypeScript 类型定义
  • Composition API 更好地支持类型推断
  • <script setup> 语法自动推导类型
  • 提供了 definePropsdefineEmits 宏,支持类型定义
  • 与 TypeScript 编译器更好地集成

面试题

1. 请解释 Vue3 的 Composition API

Composition API 是 Vue3 引入的一种新的代码组织方式,允许开发者按功能组织代码,而不是按选项类型。它的主要优势包括:

  • 更好的代码组织:将相关的逻辑放在一起,提高代码的可读性和可维护性
  • 更好的类型推断:与 TypeScript 更好地集成
  • 更好的代码复用:通过自定义 hooks 复用逻辑
  • 更灵活的逻辑组合:可以根据需要组合多个逻辑

2. 请解释 Vue3 的响应式系统

Vue3 使用 Proxy 实现响应式系统,具体步骤如下:

  1. 使用 Proxy 包装目标对象,拦截对象的读取、设置、删除等操作
  2. 当读取属性时,收集依赖(将当前的副作用函数添加到依赖集合中)
  3. 当修改属性时,触发依赖(执行所有收集的副作用函数)
  4. 对于嵌套对象,会递归地创建 Proxy

相比 Vue2 的 Object.defineProperty,Proxy 具有以下优势:

  • 可以监听到对象的添加、删除操作
  • 可以监听到数组的索引和 length 变化
  • 不需要初始化时遍历所有属性
  • 性能更好

3. 请解释 setup 函数的作用和执行时机

setup 函数是 Composition API 的核心,它的作用是:

  • 提供一个场所来使用 Composition API
  • 可以返回数据和方法,暴露给模板使用
  • 可以访问 props 和 context

setup 函数的执行时机:

  • 在组件实例创建之前执行
  • beforeCreate 钩子之前执行
  • 组件卸载时,会自动清理 setup 中创建的响应式数据和副作用

4. 请解释 watch 和 watchEffect 的区别

  • watch

    • 需要明确指定要监听的数据源
    • 可以获取新旧值
    • 懒执行,只有当监听的数据源变化时才会执行
    • 可以配置深度监听和立即执行
  • watchEffect

    • 自动追踪依赖的响应式数据
    • 无法获取新旧值
    • 立即执行,然后在依赖变化时重新执行
    • 更简洁,适合处理副作用

5. 请解释 Vue3 的组件通信方式

Vue3 提供了多种组件通信方式:

  • props:父组件向子组件传递数据
  • emit:子组件向父组件传递事件
  • provide/inject:祖孙组件之间的通信
  • Pinia:全局状态管理
  • mitt:事件总线,适用于任意组件之间的通信
  • $attrs/$listeners:传递未被声明为 props 的属性和事件

6. 请解释 Teleport 和 Suspense 的作用

  • Teleport:允许将组件的内容渲染到 DOM 树的其他位置,而不是组件的父级 DOM 中。这在处理模态框、弹出菜单等需要脱离正常 DOM 层次结构的场景时非常有用。

  • Suspense:用于在等待异步组件加载时显示一个占位内容。它可以与异步组件和 defineAsyncComponent 配合使用,提供更好的用户体验。

7. 请解释 Vue3 的性能优化措施

Vue3 在性能方面做了很多优化:

  • 编译优化

    • 静态提升:将静态节点和属性提升到渲染函数外部
    • 预编译:将模板预编译为渲染函数
    • 树摇:移除未使用的代码
  • 运行时优化

    • 使用 Proxy 实现响应式系统,性能更好
    • 虚拟 DOM 优化:更高效的 diff 算法
    • 组件更新优化:只更新变化的部分
  • 开发者优化

    • v-memo:缓存模板片段
    • shallowRef 和 shallowReactive:浅响应式
    • 组合式 API:更好的代码组织和复用

8. 请解释 Vue3 与 TypeScript 的集成

Vue3 对 TypeScript 提供了更好的支持:

  • 内置 TypeScript 类型定义
  • Composition API 更好地支持类型推断
  • <script setup> 语法自动推导类型
  • 提供了 definePropsdefineEmits 宏,支持类型定义
  • 与 TypeScript 编译器更好地集成

9. 请解释 Pinia 与 Vuex 的区别

Pinia 是 Vue3 的官方推荐状态管理库,与 Vuex 相比,它具有以下优势:

  • 更简洁的 API:不需要 mutations,直接在 actions 中修改状态
  • 更好的 TypeScript 支持:内置类型定义,更好的类型推断
  • 模块化设计:支持多个 store,每个 store 都是独立的
  • 响应式数据:使用 Vue3 的响应式系统
  • DevTools 支持:提供更好的开发工具集成

10. 请解释 Vue3 的生命周期钩子

Vue3 的生命周期钩子与 Vue2 有所不同,它使用组合式 API 的方式调用:

  • onBeforeMount:组件挂载前
  • onMounted:组件挂载后
  • onBeforeUpdate:组件更新前
  • onUpdated:组件更新后
  • onBeforeUnmount:组件卸载前
  • onUnmounted:组件卸载后
  • onErrorCaptured:捕获子组件错误
  • onRenderTracked:跟踪渲染依赖
  • onRenderTriggered:触发渲染更新

11. 请解释 Vue3 的自定义指令

Vue3 的自定义指令与 Vue2 类似,但使用了新的 API:

javascript
app.directive('focus', {
  mounted(el) {
    el.focus()
  }
})

自定义指令可以定义以下钩子函数:

  • created:指令绑定到元素时调用
  • beforeMount:元素挂载前调用
  • mounted:元素挂载后调用
  • beforeUpdate:元素更新前调用
  • updated:元素更新后调用
  • beforeUnmount:元素卸载前调用
  • unmounted:元素卸载后调用

12. 请解释 Vue3 的动态组件和 keep-alive

  • 动态组件:使用 <component :is="componentName"> 可以根据条件渲染不同的组件

  • keep-alive:可以缓存组件的状态,避免组件被频繁销毁和重建

vue
<keep-alive>
  <component :is="currentComponent" />
</keep-alive>

13. 请解释 Vue3 的模块化与组件拆分规范

Vue3 的模块化与组件拆分规范:

  • 单一职责:每个组件只负责一个功能
  • 可复用性:设计可复用的组件
  • 可维护性:代码结构清晰,易于理解和维护
  • 性能优化:避免不必要的渲染和计算

目录结构示例:

src/
├── components/         # 通用组件
├── views/             # 页面组件
├── router/            # 路由配置
├── stores/            # 状态管理
├── api/               # API 调用
├── utils/             # 工具函数
├── hooks/             # 自定义 hooks
├── App.vue            # 根组件
└── main.js            # 入口文件

14. 请解释 Vue3 的路由守卫

Vue3 的路由守卫与 Vue2 类似,包括:

  • 全局前置守卫router.beforeEach
  • 全局解析守卫router.beforeResolve
  • 全局后置守卫router.afterEach
  • 路由独享守卫:在路由配置中定义 beforeEnter
  • 组件内守卫beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave

路由守卫用于控制路由的访问权限、处理导航逻辑等。

15. 请解释 Vue3 的 API 调用封装

Vue3 的 API 调用封装通常包括:

  • 创建 axios 实例,配置 baseURL、超时时间等
  • 添加请求拦截器,处理 token、请求参数等
  • 添加响应拦截器,处理响应数据、错误等
  • 封装 API 方法,按模块组织
javascript
// api/request.js
import axios from 'axios'

const request = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000
})

// 请求拦截器
request.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
request.interceptors.response.use(
  response => {
    return response.data
  },
  error => {
    // 处理错误
    return Promise.reject(error)
  }
)

export default request

通过本章的学习,我们了解了 Vue3 的常见问题和面试题,这将帮助我们更好地理解和掌握 Vue3,为面试做好准备。Vue3 是一个强大的前端框架,掌握它的核心概念和最佳实践,将有助于我们构建更好的前端应用。

© 2026 编程马·菜鸟教程 版权所有