一、Vue 基础
1. Vue 的生命周期钩子有哪些?分别在什么阶段触发?
答:
-
Vue 2:
beforeCreate→created→beforeMount→mounted→beforeUpdate→updated→beforeDestroy→destroyed. -
Vue 3:
类似 Vue 2,但beforeDestroy和destroyed改为beforeUnmount和unmounted. -
关键阶段:
created:实例创建完成,数据观测已初始化,但 DOM 未生成。mounted:DOM 挂载完成,可操作 DOM 或调用第三方库。updated:数据更新导致 DOM 重新渲染后触发。
2. Vue 组件间通信有哪些方式?
答:
-
父子组件:
props/$emitv-model(语法糖,等价于:value+@input)$parent/$children(不推荐)
-
兄弟组件:
- 事件总线(Event Bus)
- Vuex/Pinia(状态管理)
-
跨层级组件:
provide/inject- Vuex/Pinia
-
任意组件:
- 全局事件总线(
app.config.globalProperties.$bus) - 状态管理库
- 全局事件总线(
3. v-if 和 v-show 的区别是什么?
答:
v-if:动态添加/移除 DOM 元素,适合切换频率低的场景。v-show:通过 CSSdisplay: none控制显示,适合频繁切换的场景。- 性能:
v-if有更高的切换开销,v-show有更高的初始渲染开销。
二、Vue 进阶
4. Vue 的响应式原理是什么?
答:
-
Vue 2:
- 使用
Object.defineProperty劫持对象属性的getter/setter。 - 通过
Dep(依赖收集器)和Watcher(观察者)实现依赖追踪和派发更新。 - 缺点:无法检测对象属性的添加/删除,需用
Vue.set/Vue.delete。
- 使用
-
Vue 3:
- 使用
Proxy代理整个对象,支持动态新增属性和数组索引修改。 - 通过
Reflect操作对象属性,effect函数管理依赖。
- 使用
5. Vue 3 的 Composition API 解决了什么问题?
答:
-
逻辑复用:Options API 中逻辑分散在
data、methods等选项中,Composition API 通过setup函数集中管理逻辑。 -
类型推导:更好的 TypeScript 支持。
-
代码组织:按功能而非选项组织代码。
-
示例:
javascript
复制
import { ref, computed } from 'vue'; export default { setup() { const count = ref(0); const double = computed(() => count.value * 2); return { count, double }; } };
6. Vue 的虚拟 DOM 和 Diff 算法是如何工作的?
答:
-
虚拟 DOM:轻量级的 JavaScript 对象,描述真实 DOM 结构。
-
Diff 算法:
- 同级比较:只比较同一层级的节点。
- Key 的作用:通过唯一
key识别节点,减少不必要的渲染。 - 双端比较:Vue 3 采用优化的双端对比算法,减少移动次数。
三、Vue 状态管理
7. Vuex 的核心概念是什么?
答:
- State:单一状态树,存储全局状态。
- Getters:从 State 派生的计算属性。
- Mutations:同步修改 State 的方法(通过
commit调用)。 - Actions:异步操作,可调用 Mutations(通过
dispatch调用)。 - Modules:将 Store 分割为模块,避免单一 Store 臃肿。
8. Pinia 和 Vuex 的区别是什么?为什么推荐 Pinia?
答:
-
Pinia 优势:
- 更简洁的 API(无
mutations,直接修改state)。 - 支持 Composition API 和 TypeScript。
- 自动代码分割,无需手动划分模块。
- 更简洁的 API(无
-
核心概念:
defineStore定义 Store。state、getters、actions三部分。
四、Vue 路由
9. Vue Router 的导航守卫有哪些?
答:
-
全局守卫:
beforeEach:路由跳转前触发。afterEach:路由跳转后触发。
-
路由独享守卫:
beforeEnter。 -
组件内守卫:
beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave
10. 如何实现路由懒加载?
答:
-
Vue 2:
javascript
复制
const Home = () => import('./views/Home.vue'); -
Vue 3(结合 Webpack 动态导入):
javascript
复制
{ path: '/home', component: () => import('./views/Home.vue') } -
原理:利用 Webpack 的代码分割功能,按需加载组件。
五、性能优化
11. 如何优化 Vue 项目的首屏加载速度?
答:
- 代码分割:路由懒加载、组件异步加载。
- CDN 加速:将第三方库(如 Vue、Vuex)通过 CDN 引入。
- Gzip 压缩:服务端开启 Gzip 压缩。
- 预渲染/SSR:对静态页面使用预渲染(prerender-spa-plugin),动态内容用 SSR(Nuxt.js)。
12. 如何避免 Vue 中的内存泄漏?
答:
- 销毁定时器/事件监听:在
beforeUnmount或unmounted生命周期中清除。 - 避免全局变量:组件内变量应在组件销毁时释放。
- 第三方库管理:如 ECharts、Three.js,需手动调用
dispose()方法。
六、实战场景
13. 如何实现一个全局的 Loading 组件?
答:
-
方案:
-
使用 Vue 插件机制注册全局组件。
-
通过服务(Service)模式调用:
javascript
复制
// loading.js import { createApp } from 'vue'; const app = createApp({}); export const showLoading = () => app.$loading.show(); export const hideLoading = () => app.$loading.hide(); -
在 Axios 拦截器中控制显示/隐藏。
-
14. Vue 项目中如何实现权限控制?
答:
-
路由权限:
- 在
beforeEach导航守卫中校验用户角色,动态添加路由(router.addRoute)。
- 在
-
按钮权限:
- 自定义指令
v-permission,根据权限表隐藏按钮。
- 自定义指令
-
API 权限:后端接口校验用户 Token 和角色。
七、高级原理
15. Vue 3 的 Teleport 组件有什么作用?
答:
-
功能:将组件内容渲染到 DOM 树的任意位置(如全局弹窗、模态框)。
-
示例:
html
复制
<teleport to="body"> <div class="modal">这是一个全局弹窗</div> </teleport>运行 HTML
16. Vue 3 的 Fragment 和 Suspense 是什么?
答:
- Fragment:允许组件返回多个根节点(无需外层包裹
<div>)。 - Suspense:处理异步组件加载状态,提供
fallback插槽展示加载中状态。
八、综合问题
17. 你在 Vue 项目中遇到过哪些棘手问题?如何解决的?
答:
- 问题 1:长列表渲染卡顿。
解决:使用虚拟滚动(vue-virtual-scroller)。 - 问题 2:动态表单校验复杂。
解决:结合async-validator和动态渲染表单项。 - 问题 3:多层级组件通信混乱。
解决:使用 Provide/Inject + 响应式对象集中管理状态。
18. 如何实现 Vue 项目的国际化(i18n)?
答:
-
方案:
- 使用
vue-i18n库。 - 定义多语言 JSON 文件(如
en.json、zh-CN.json)。 - 在 Vue 组件中通过
$t('key')调用翻译内容。 - 结合路由切换语言(保存到 localStorage)。
- 使用
附:高频考点总结
| 类别 | 高频问题 |
|---|---|
| 原理 | 响应式原理、虚拟 DOM、Diff 算法 |
| 组件 | 通信方式、生命周期、动态组件 |
| 状态管理 | Vuex 核心概念、Pinia 优势 |
| 路由 | 导航守卫、懒加载、动态路由 |
| 性能优化 | 首屏加载、内存泄漏、代码分割 |
以上问题覆盖了 Vue 技术栈的核心知识点,建议结合官方文档和实际项目经验深入理解。