Vue 前端面试题(含答案)大全 v2025
Vue 前端面试题(含答案)大全 v2025
覆盖 Vue2/3 核心、Composition API、响应式原理、组件通信、指令、路由与状态管理(Vuex/Pinia)、性能优化、SSR/Nuxt、TypeScript、构建工具(Vite/Webpack)、测试、安全与可访问性、工程化与最佳实践。示例代码默认以 Vue 3 + Vite +
<script setup>
为主,并注明 Vue 2 差异。
一、基础与生态
1. 什么是 Vue?与 React、Angular 的主要区别?
Vue 是渐进式前端框架,主打视图层 + 生态解耦(路由、状态管理按需选)。对比:React 函数式、JSX 心智;Angular 一体化、强约束;Vue 模板/指令友好、学习曲线平缓,Composition API 兼具灵活与组织性。
2. Vue2 与 Vue3 的核心变化?
- 响应式:Object.defineProperty → Proxy(更好覆盖新增/删除属性、数组下标等)。
- API:Options API → Composition API;新增
<script setup>
、Teleport、Fragments。 - 构建:官方推荐 Vite;Tree-shaking 更友好;性能/体积优化。
- TS 友好度显著提升;自定义渲染器/内部架构重写(monorepo)。
3. 什么是渐进式框架?
可从小到大逐步引入能力:仅视图层 → 加上 Vue Router → 加上 Pinia/Vuex → SSR/Nuxt。
4. 模板语法与 JSX 的取舍?
模板({{}}
+ 指令)表达 UI 更直观;JSX 灵活、可与 TS 深度结合。Vue 3 两者都支持,按团队偏好与场景选择。
5. 单文件组件(SFC)的组成?
<template>
+ <script>
(或 <script setup>
)+ <style scoped>
,可加 <style module>
、<style lang="scss">
、<script lang="ts">
。
二、响应式与渲染机制
6. Vue3 响应式如何实现?
基于 Proxy
拦截 get/set
/has
/deleteProperty
,依赖收集(track)与触发(trigger)驱动 effect
重新执行,最小化更新。
7. 依赖收集发生在何时?
首次访问响应式数据(get
)时在当前活跃 effect
上收集;数据变更(set
)时精确触发相关 effect
。
8. ref
与 reactive
区别?
ref
包装原始值或对象(通过 .value
访问);reactive
仅用于对象/数组/Map/Set 等。模板中 ref
会自动解包。
9. 何时需要 toRef
/ toRefs
?
将 reactive
对象的属性以 ref
形式暴露,防止解构丢失响应性。
10. shallowRef
/ shallowReactive
用途?
只追踪顶层变化,适用于大型不可变数据/第三方实例(如图表对象)以减少开销。
11. 为何需要 markRaw
与 toRaw
?
markRaw
标记对象不被代理;toRaw
获取原始对象,常用于与非响应式库交互或性能优化。
12. computed
与 watch
区别与使用时机?
computed
有缓存,适用于派生状态;watch
适合副作用(请求、日志)。watchEffect
会立即执行并追踪内部依赖。
13. nextTick
的作用?
等待下一轮 DOM 更新后执行回调,常用于依赖更新后 DOM 的操作(测量、滚动)。
14. Vue2 中变更检测的坑点?
不能检测对象属性新增/删除、数组通过索引修改等;需 Vue.set
/this.$set
或替换为新数组。Vue3 已无此限制。
15. Diff 策略概览?
Vue 使用基于 key 的最小化 DOM 变更;Vue3 重写了核心算法,支持 Fragment/Teleport,diff 更快更小。
三、Composition API / <script setup>
16. 为什么引入 Composition API?
解决 Options API 在大型组件里逻辑分散(data/methods/computed 分段)的痛点,提升可复用性与类型推断。
17. 常用 API?
ref/reactive/computed/watch/watchEffect/onMounted/onUnmounted/provide/inject/getCurrentInstance
等。
18. <script setup>
的优势?
更少样板;顶层变量直接对模板可见;自动注册 defineProps/defineEmits/defineExpose
;编译期优化。
19. defineProps
/ defineEmits
/ withDefaults
用法?
在 <script setup>
中声明 props/事件与默认值:
<script setup lang="ts">
const props = withDefaults(defineProps<{ size?: 'sm'|'md'|'lg'; count: number }>(), { size: 'md' })
const emit = defineEmits<{ (e:'update:count', v:number):void }>()
</script>
20. 多组件复用逻辑如何组织?
抽成 composable(useXxx.ts
),输出状态与方法;配合依赖注入(provide/inject)实现跨层级共享。
21. expose
与 defineExpose
何用?
显式暴露子组件方法给父组件通过 ref
调用,避免暴露全部实例。
22. 在 <script setup>
如何获取组件实例?
const inst = getCurrentInstance()
(谨慎使用,仅在需要访问 appContext/plugins 时)。
四、模板与指令
23. 常见指令及场景?
v-bind
、v-on
、v-if/else/else-if
、v-show
、v-for
、v-model
、v-slot
、v-html
、v-memo
(Vue3.3+)。
24. v-if
vs v-show
?
v-if
条件渲染(销毁/重建,首屏更省);v-show
仅切换 display
(频繁切换更优)。
25. v-for
必须加 key 吗?
建议总是加稳定唯一的 key,帮助 diff 减少误复用,提高性能与正确性。
26. v-model
在 Vue3 的变化?
支持多 v-model
、自定义参数(v-model:title
),事件名为 update:modelValue
;可用 defineModel
(3.4+)简化双向绑定。
27. 具名插槽与作用域插槽?
<slot name="header"/>
具名;作用域插槽通过 v-slot="slotProps"
传值,由父读取子提供的数据。
28. v-html
风险?
容易引入 XSS,仅用于可信内容,并做好服务端过滤/转义。
29. 条件与循环混用反模式?
在同一元素上 v-if
+v-for
会先循环再判断,建议外层包容器或用计算属性过滤数据。
五、组件通信
30. 父子通信?
父→子:props;子→父:emit
;双向:v-model
/defineModel
。
31. 兄弟通信?
通过父中转、事件总线(小型场景)或状态管理(Pinia/Vuex)。
32. 跨层级通信?
provide/inject
共享,或使用状态库。
33. 全局事件总线是否推荐?
仅限极小项目或一次性原型;中大型项目更建议 Pinia/Vuex。
六、路由(Vue Router 3/4)
34. Hash 与 History 模式?
Hash 依赖 #
,无需服务端配置;History 更优雅但需服务端回退到 index.html
。
35. 动态路由与路由守卫?
动态:addRoute
/基于权限生成;守卫:beforeEach/afterEach
,组件内 beforeRouteEnter
等。常用做鉴权、埋点。
36. 路由懒加载?
component: () => import('...')
,结合分包策略提升首屏速度。
37. 路由传参与刷新丢失问题?
params
需命名路由并在路径中声明;或改用 query
,或持久化到 store/localStorage。
38. 滚动行为控制?
scrollBehavior(to, from, savedPosition)
恢复滚动、锚点定位。
七、状态管理(Vuex / Pinia)
39. Pinia 与 Vuex 区别?
Pinia 轻量、TS 友好、与 Composition API 自然融合;Vuex 4 兼容 Vue3,但写法偏模板化。新项目推荐 Pinia。
40. Pinia 基本用法?
定义 store:
// stores/user.ts
import { defineStore } from 'pinia'
export const useUser = defineStore('user', {state: () => ({ token: '', profile: null as null | {id:string,name:string} }),actions: { login(t:string){ this.token=t } }
})
组件内:const user = useUser()
;支持持久化(插件)、跨页面共享。
41. 何时不需要全局状态?
仅页面局部使用的数据用组件状态即可,避免过度全局化。
42. 派生状态放哪里?
Pinia 可用 getters
,或在组件用 computed
,避免重复计算与副作用。
八、网络请求与数据流
43. 在何处发起请求?
常在 onMounted
、watch
(依赖变动)或路由钩子里;SSR 场景需在服务端预取并脱水。
44. 如何取消请求与避免竞态?
使用 AbortController
/axios 取消;在 watch
返回清理函数;用请求标记避免旧响应覆盖新数据。
45. 接口错误统一处理?
封装 http 模块/拦截器;全局错误边界(onErrorCaptured
)、路由守卫兜底到错误页。
九、生命周期(Vue3 对照 Vue2)
46. 关键钩子映射
beforeCreate/created
→setup
beforeMount/mounted
→onBeforeMount/onMounted
beforeUpdate/updated
→onBeforeUpdate/onUpdated
beforeDestroy/destroyed
→onBeforeUnmount/onUnmounted
- 新增:
onActivated/onDeactivated
(配合 KeepAlive)、onErrorCaptured
、onRenderTracked/Triggered
(调试)。
47. KeepAlive 使用?
缓存动态组件/路由组件状态,提高切换性能;配合 include/exclude
与 max
控制缓存范围。
十、性能优化
48. 列出 10 条常见优化手段
- 路由与组件懒加载 2) 拆包/代码分割 3) 使用
defineAsyncComponent
4) 稳定key
5) 避免在模板中执行重计算(用computed
) 6)v-memo
/shallowRef
控制渲染 7) 大列表虚拟滚动 8) 图片懒加载/预设尺寸 9) SSR/预渲染 10) 生产环境关闭 devtool 与 verbose 日志。
49. 大列表如何优化?
虚拟列表(Vue Virtual Scroller)、分片渲染(requestIdleCallback)、骨架屏、占位符。
50. 何时手动 cache
/memo
?
纯函数且依赖不变、渲染昂贵时;Vue3.3 v-memo
可缓存子树。
51. 避免不必要的响应式?
对静态大对象使用 markRaw
;只在需要变更的点上使用 ref
;使用 shallowRef
保存第三方实例。
十一、样式与 CSS 方案
52. scoped
的原理?
通过属性选择器(如 [data-v-xxx]
)限制样式作用域;注意深度选择需 :deep()
。
53. CSS Modules 与 scoped
区别?
Modules 通过哈希类名隔离,适合 TS/JS 驱动的样式组合;scoped
偏模板隔离。
54. 原子化/实用类(Tailwind)与传统 CSS?
原子类提高复用与一致性;传统 CSS 语义更清晰。混合使用需制定规范。
十二、表单与校验
55. 多层嵌套表单的可维护写法?
使用 v-model
+ defineModel
、受控组件、vee-validate
/@vueuse/form
,组合式抽出校验逻辑。
56. 自定义表单组件如何与 v-model
对齐?
接收 modelValue
、发出 update:modelValue
;或 Vue3.4+ 使用 defineModel
。
十三、指令与插件
57. 自定义指令场景?
权限控制(置灰/隐藏)、懒加载、拖拽、点击外部、粘贴处理。
58. 指令生命周期钩子?
created/beforeMount/mounted/beforeUpdate/updated/beforeUnmount/unmounted
。
59. 如何封装全局插件?
暴露 install(app){ ... }
注册全局组件/指令/原型方法,配置通过 app.use(Plugin, options)
传入。
十四、SSR 与 Nuxt
60. SSR 的优缺点?
优:首屏快、SEO 友好;缺:服务端开销、状态同步复杂、缓存策略需要设计。
61. 基本思路?
服务端渲染 HTML → 客户端 hydrate 接管。数据需在服务端预取并注水(dehydrate/hydrate)。
62. Nuxt 关键点?
基于约定的文件结构、内置路由与数据获取(useAsyncData
)、自动代码分割、服务器 API 路由。
十五、TypeScript 与类型推断
63. Vue3 对 TS 友好在哪里?
defineProps/defineEmits
泛型、<script setup lang="ts">
、Pinia 原生类型、Volar 支持。
64. 如何为 emit
类型化?
const emit = defineEmits<{(e:'save', payload:{id:string}):void}>()
。
65. 组件公共 API 的类型导出?
使用 defineExpose
暴露方法类型,或导出 props/事件类型给外部复用。
十六、构建工具(Vite / Webpack)
66. 为什么推荐 Vite?
基于原生 ESM + esbuild 预构建,冷启动快;Rollup 生产构建,生态完善(Vue 官方插件)。
67. 常见 Vite 优化?
依赖预构建(optimizeDeps)、按需引入、分包(manualChunks)、CDN 外链、build.target
/minify
设置。
68. 环境变量管理?
.env.[mode]
,通过 import.meta.env
访问;前缀 VITE_
暴露给客户端。
十七、测试(Vitest/Jest、Cypress/Playwright)
69. 组件单测要点?
浅/深渲染、事件触发、异步更新(await nextTick()
)、快照、可访问性断言(aria-*
)。
70. 如何 mock 网络与路由?
使用 msw
/vi.mock
;提供 router
与 pinia
测试实例;隔离副作用。
71. E2E 测试策略?
关键用户路径优先,稳定选择器(data-test
),并发/重试、截图与视频留存。
十八、安全与可访问性
72. 常见前端安全问题?
XSS(v-html
)、CSRF(同源策略/Token/双重 Cookie)、点击劫持(X-Frame-Options
)、敏感信息泄露。
73. 如何防 XSS?
服务端转义、CSP、避免直接拼接 HTML、可信白名单、组件内谨慎使用 v-html
。
74. A11y 要点?
语义化标签、焦点管理、键盘可操作、对比度、aria-*
属性、为动态内容提供可达提示。
十九、国际化与多语言
75. vue-i18n
的基本用法?
创建 i18n 实例,<i18n-t>
富文本翻译,占位/复数处理;懒加载语言包与持久化语言偏好。
二十、工程化与最佳实践
76. 代码组织与命名规范?
按领域/路由分模块;组件 Base
/App
前缀;composables 放 src/composables
;样式变量集中化。
77. 提交规范与 CI?
Commitlint + Husky + Lint-Staged;ESLint + Prettier;CI 执行测试与构建。
78. 图标与资源管理?
Iconify/Unplugin Icons;图片资源使用 srcset
与构建期压缩。
79. 版本与发布?
语义化版本、变更日志、灰度发布/特性开关、Sentry 监控。
80. 常见代码味道?
胖组件、滥用全局状态、watch
里做业务堆叠、过多 any
、硬编码 URL/常量。
二十一、经典代码题与场景题
81. 实现一个可复用的防抖/节流 composable
// useDebounce.ts
export function useDebounce<T>(value: T, delay = 300){const v = ref(value) as Ref<T>let t: number | undefinedwatch(() => value, (nv) => {clearTimeout(t)t = window.setTimeout(() => (v.value = nv), delay)})return v
}
82. 封装一个 useFetch
export function useFetch<T>(url: MaybeRef<string>){const data = ref<T | null>(null)const error = ref<unknown>(null)const loading = ref(false)const controller = ref<AbortController | null>(null)async function run(){loading.value = truecontroller.value?.abort()controller.value = new AbortController()try{const res = await fetch(unref(url), { signal: controller.value.signal })data.value = await res.json()}catch(e){ error.value = e }finally{ loading.value = false }}onMounted(run)return { data, error, loading, run, cancel: () => controller.value?.abort() }
}
83. 父子组件双向绑定(defineModel
版)
<!-- Child.vue -->
<script setup lang="ts">
const model = defineModel<string>()
</script>
<template><input v-model="model" />
</template>
84. 大列表虚拟滚动的思路?
只渲染可视区 + 缓冲区,计算偏移量定位容器高度;监听滚动计算首尾索引。
85. 自定义指令:点击外部关闭
export const clickOutside = {beforeMount(el: any, binding: any){el.__handler__ = (e: MouseEvent) => {if(!el.contains(e.target)) binding.value(e)}document.addEventListener('click', el.__handler__)},unmounted(el: any){document.removeEventListener('click', el.__handler__)}
}
86. 路由鉴权示例
router.beforeEach((to, from, next) => {const user = useUser()if(to.meta.requiresAuth && !user.token) next({ name: 'login', query: { redirect: to.fullPath } })else next()
})
87. 错误边界捕获
onErrorCaptured((err, instance, info) => {console.error(err, info)return false // 向上传播
})
二十二、开放题(可扩展)
88. 设计一套组件库的技术方案:
- 技术栈:Vue3 + TS + Vite + Vitest + Playwright
- 规范:按需加载、样式 tokens、图标方案、文档站(VitePress)
- 质量:单测覆盖、视觉回归、a11y 校验、CI 发布(changeset)。
89. 业务中如何拆分“胖组件”?
识别职责并抽出 composables;数据获取/状态分离;呈现组件(presentational)与容器组件(container)分层。
90. 在微前端架构中接入 Vue 应用?
使用 qiankun/Module Federation;公共依赖外链;路由隔离与沙箱;状态通过事件总线或 shared store 同步。
二十三、Vue2 兼容与迁移
91. 迁移注意点
- 过滤器(filters)移除:用计算属性/方法代替
$listeners/$attrs
合并行为变化;v-model
事件名变化- 插槽语法(
slot-scope
→v-slot
) - 全局 API 迁移到
app.config.globalProperties
/app.use()
。
92. 常见迁移策略
- 先升级依赖与构建工具 → 消除警告 → 引入组合式重构复杂组件 → 单元测试保障回归。
二十四、杂项高频问答
93. teleport
用于什么?
将子树渲染到 DOM 的另一个位置,例如全局模态、悬浮层。
94. fragments
是什么?
多根节点组件支持;Vue2 需要包一层容器,Vue3 可直接返回数组模板。
95. 如何监听组件尺寸或元素可见?
ResizeObserver
、IntersectionObserver
,配合 @vueuse/core
(如 useElementSize
)。
96. SSR 中如何避免水合不一致?
仅在客户端访问浏览器 API;使用 client-only
/<Suspense>
;确保初始数据一致。
97. 如何优雅处理权限按钮显示?
自定义指令或组件包裹,基于权限表判断;禁用与隐藏策略分离;审计埋点。
98. 如何处理长列表选择/勾选性能?
受控集合结构(Set),惰性渲染复选框;批量更新(事务化);虚拟滚动。
99. 如何定位响应式性能瓶颈?
onRenderTracked/Triggered
调试;性能面板采样;标记关键 computed
与 watch
的依赖图。
100. 你最常用的 Vue 工具库?为什么?
@vueuse/core
(高质量 composables)、Pinia、Vue Router、VitePress、Iconify、UnoCSS/Tailwind、Vitest/Testing Library。
附录 A:面试速查清单(提纲)
- Vue3 响应式:Proxy/track/trigger/effect;
ref/reactive/computed/watch
- 组件通信:props/emit/v-model/provide-inject/store
- 路由:懒加载、守卫、动态路由、滚动恢复
- 状态:Pinia vs Vuex;何时全局
- 性能:分包、虚拟列表、
v-memo
、markRaw
- SSR/Nuxt:hydrate、数据脱水、缓存
- TS:
defineProps/Emits
泛型,<script setup>
- 工程化:Vite、ESLint/Prettier、CI、监控
- 安全/A11y:XSS、CSP、aria
提示:根据岗位 JD,选择性深挖以上任意模块并准备代码 Demo(虚拟列表、指令、composable、路由鉴权、错误边界等)。