Appearance
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 实现响应式系统:
- 使用 Proxy 包装目标对象,拦截对象的读取、设置、删除等操作
- 当读取属性时,收集依赖(将当前的副作用函数添加到依赖集合中)
- 当修改属性时,触发依赖(执行所有收集的副作用函数)
- 对于嵌套对象,会递归地创建 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>语法自动推导类型- 提供了
defineProps和defineEmits宏,支持类型定义 - 与 TypeScript 编译器更好地集成
面试题
1. 请解释 Vue3 的 Composition API
Composition API 是 Vue3 引入的一种新的代码组织方式,允许开发者按功能组织代码,而不是按选项类型。它的主要优势包括:
- 更好的代码组织:将相关的逻辑放在一起,提高代码的可读性和可维护性
- 更好的类型推断:与 TypeScript 更好地集成
- 更好的代码复用:通过自定义 hooks 复用逻辑
- 更灵活的逻辑组合:可以根据需要组合多个逻辑
2. 请解释 Vue3 的响应式系统
Vue3 使用 Proxy 实现响应式系统,具体步骤如下:
- 使用 Proxy 包装目标对象,拦截对象的读取、设置、删除等操作
- 当读取属性时,收集依赖(将当前的副作用函数添加到依赖集合中)
- 当修改属性时,触发依赖(执行所有收集的副作用函数)
- 对于嵌套对象,会递归地创建 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>语法自动推导类型- 提供了
defineProps和defineEmits宏,支持类型定义 - 与 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 - 组件内守卫:
beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
路由守卫用于控制路由的访问权限、处理导航逻辑等。
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 是一个强大的前端框架,掌握它的核心概念和最佳实践,将有助于我们构建更好的前端应用。
