Vue 高频面试题 50 道
这里汇总了 50 道 Vue.js 开发岗位常问的面试题,涵盖 Vue 2、Vue 3、原理及生态系统。
一、Vue 基础 (1-10)
- Vue 的核心特性是什么?
- 数据驱动 (MVVM):自动将数据渲染到视图。
- 组件化:提高复用性和可维护性。
- 指令系统:
v-if,v-for,v-model等。
v-show和v-if的区别?v-if是真正的条件渲染,条件为假时不渲染 DOM(销毁/重建)。适合不常切换的场景。v-show始终渲染 DOM,通过 CSSdisplay: none控制显隐。适合频繁切换的场景。
v-for中key的作用是什么?key是虚拟 DOM 节点的唯一标识。Vue 的 Diff 算法通过key判断新旧节点是否是同一个,从而复用节点,提高渲染性能。- 注意:避免使用 index 作为 key,这会在列表顺序变化时导致状态错乱。
- Vue 的生命周期有哪些(Vue 2 vs Vue 3)?
- Vue 2:
beforeCreate,created(数据可用),beforeMount,mounted(DOM可用),beforeUpdate,updated,beforeDestroy,destroyed. - Vue 3: 大部分对应,但 Destroy 改为
beforeUnmount,unmounted. 组合式 API 中使用onMounted等。
- Vue 2:
- Vue 组件间通信有哪些方式?
- 父子:
props/$emit,$parent/$children,ref. - 跨级:
provide/inject,$attrs/$listeners. - 兄弟/任意: EventBus (Vue 2), Vuex / Pinia, Mitt (Vue 3).
- 父子:
computed和watch的区别?- computed: 计算属性,依赖其他属性计算值,有缓存(依赖不变不重新计算),不支持异步。
- watch: 监听属性,数据变化时执行回调,支持异步和开销大的操作,无缓存。
v-model的原理是什么?- 本质是语法糖。
- 在
input元素上::value="data" @input="data = $event.target.value"。 - 在组件上:Vue 2 是
:value+@input(或model选项配置);Vue 3 是:modelValue+@update:modelValue。
nextTick是什么?有什么用?- Vue 的 DOM 更新是异步的。
nextTick接受一个回调,在下一次 DOM 更新循环结束之后执行。 - 用途:修改数据后,立即获取更新后的 DOM。
- Vue 的 DOM 更新是异步的。
- 为什么 data 在组件中必须是一个函数?
- 为了保证每个组件实例维护一份独立的 data 副本。如果 data 是对象,所有实例将共享同一个数据对象(引用)。
- Vue 如何检测数组变化?
- Vue 2 拦截了数组的 7 个变异方法 (
push,pop,shift,unshift,splice,sort,reverse) 来触发更新。直接修改索引 (arr[0]=1) 无法检测。 - Vue 3 使用 Proxy,可以直接检测数组索引和长度变化。
- Vue 2 拦截了数组的 7 个变异方法 (
二、Vue 3 新特性 (11-20)
- Vue 2 和 Vue 3 的主要区别?
- 响应式原理: Vue 2 (Object.defineProperty) vs Vue 3 (Proxy).
- API 风格: Options API vs Composition API.
- 性能: Vue 3 更快,体积更小,Tree-shaking 支持更好。
- 新组件: Fragment, Teleport, Suspense.
- Composition API (组合式 API) 的优势?
- 更好的逻辑复用 (Composables)。
- 代码按业务逻辑组织,而非按选项 (data/methods) 分割,利于维护大型组件。
- 更好的 TypeScript 类型推导。
Object.defineProperty和Proxy的区别?defineProperty: 只能劫持对象的属性,需要遍历;无法监听新增/删除属性;无法监听数组下标。Proxy: 劫持整个对象;支持数组;性能更好;懒代理(嵌套对象深层)需手动处理。
- Vue 3 中的
ref和reactive有什么区别?ref: 用于基本数据类型(也可以包对象),通过.value访问。reactive: 用于对象/数组,基于 Proxy,直接访问属性,不能解构(会丢失响应性,需用toRefs)。
- 什么是 Teleport?
- 将组件内部的 DOM 渲染到当前组件树之外的节点(如
body),常用于 Modal、Toast。
- 将组件内部的 DOM 渲染到当前组件树之外的节点(如
- Vue 3 的生命周期钩子有何变化?
beforeCreate/created->setup()mounted->onMounteddestroyed->onUnmounted
<script setup>是什么?- Composition API 的语法糖。代码更简洁,顶层变量直接在模板可用,无需
return。
- Composition API 的语法糖。代码更简洁,顶层变量直接在模板可用,无需
- Vue 3 如何实现 Tree-shaking?
- 大部分全局 API (如
nextTick,defineComponent) 改为具名导出,未使用的功能在打包时会被移除。
- 大部分全局 API (如
- WatchEffect 和 Watch 的区别?
watchEffect: 自动收集依赖,立即执行一次。watch: 需显式指定数据源,默认只有变化时执行(除非immediate: true)。
- Vue 3 为什么支持 Fragment(多根节点)?
- Vue 3 的渲染引擎通过虚拟 DOM 的打平,不再强制要求组件必须有一个根节点,减少了无意义的 wrapper div。
三、Vue 原理 (21-30)
- 简述 Vue 的响应式原理 (Vue 2)。
- Observer: 遍历 data,用
Object.defineProperty将属性转为 getter/setter。 - Dep: 依赖收集器,属性 getter 时收集 Watcher,setter 时通知 Watcher。
- Watcher: 订阅者,收到通知后执行回调更新视图。
- Observer: 遍历 data,用
- 简述 Vue 的 Diff 算法 (双端 Diff)。
- 同层比较,不跨级。
- Vue 2 采用双端比较:新旧列表的 头头、尾尾、头尾、尾头 依次尝试对比,若都没中则查 Map。
- Vue 3 采用最长递增子序列算法来优化乱序移动的情况。
- 虚拟 DOM (Virtual DOM) 真的比真实 DOM 快吗?
- 不一定。首次渲染由于要创建 VDOM,比直接 innerHTML 慢。
- 优势在于更新阶段,通过 Diff 算法减少了不必要的真实 DOM 操作,且具备跨平台能力。
- Vue 模板编译 (Template Compilation) 的过程?
- Template -> AST (抽象语法树) -> Optimize (标记静态节点) -> Generate (生成 render 函数字符串)。
keep-alive的原理是什么?- LRU (Least Recently Used) 缓存策略。
- 在组件切换时,不销毁组件实例,而是将其缓存到内存中。再次激活时触发
activated钩子。
- Vue 是如何处理 Slot 的?
- 普通插槽:在父组件编译,当作子组件的 props 传入。
- 作用域插槽:父组件传一个函数给子组件,子组件调用函数并传参。
$nextTick的实现原理?- 利用 JS 事件循环微任务/宏任务。优先使用
Promise.then(微任务),降级依次为MutationObserver,setImmediate,setTimeout。
- 利用 JS 事件循环微任务/宏任务。优先使用
- 为什么 Vue 2 中给对象添加新属性是非响应式的?
- 初始化时
defineProperty已经执行完毕。解决:Vue.set(obj, key, val)。
- 初始化时
- Vue 组件中的 data 为什么要是函数?
- 防止多个组件实例共享同一个数据对象(闭包特性)。
- 什么是 render 函数?
- 模板最终都会被编译成
render函数,它返回 VNode。可以直接手写 render 函数(配合 JSX)来获得更高的灵活性。
- 模板最终都会被编译成
四、Vue 全家桶 (Router & Vuex/Pinia) (31-40)
- Vue-Router 的两种模式及原理?
- Hash: URL 带
#,利用window.onhashchange监听。兼容性好。 - History: URL 无
#,利用 HTML5 History API (pushState,replaceState) 和popstate事件。需后端配置支持。
- Hash: URL 带
- Vue-Router 导航守卫有哪些?
- 全局:
beforeEach,beforeResolve,afterEach. - 路由独享:
beforeEnter. - 组件内:
beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave.
- 全局:
- Vuex 有哪几种属性?
State(数据),Getters(计算属性),Mutations(同步修改),Actions(异步操作),Modules(模块化)。
- Vuex 中 Mutation 和 Action 的区别?
- Mutation 必须是同步的,用于修改 State (DevTools 追踪)。
- Action 可以包含异步操作,通过 commit 提交 Mutation。
- Pinia 相比 Vuex 有什么优势?
- API 更简单(去掉了 Mutation,只有 State, Getters, Actions)。
- 原生支持 TypeScript。
- 体积更小,模块化更自然(不需要嵌套 module)。
- Vue-Router 中
$route和$router的区别?$route: 当前路由信息对象 (path, params, query)。$router: 路由实例,包含跳转方法 (push, replace, go)。
- 如何实现路由懒加载?
component: () => import('./MyComponent.vue')(Webpack 代码分割)。
- Vuex 是如何实现响应式的?
- Vuex 3 本质上是创建了一个 Vue 实例,将 state 存放在该实例的 data 中。
- history 模式下刷新页面 404 怎么办?
- 后端(Nginx/Apache)需配置:如果 URL 匹配不到静态资源,统一返回
index.html。
- 后端(Nginx/Apache)需配置:如果 URL 匹配不到静态资源,统一返回
- Pinia 可以在组件外使用吗?
- 可以,只要在
createPinia()安装之后即可使用。
- 可以,只要在
五、进阶与优化 (41-50)
- Vue 项目性能优化的常见手段?
- 路由懒加载。
keep-alive缓存组件。v-show复用 DOM。v-for使用正确 key,避免同时使用v-if。- 长列表虚拟滚动 (vue-virtual-scroller)。
- 图片懒加载 (v-lazy)。
- Object.freeze (Vue 2) 冻结不需要响应式的大数据。
- SPA (单页应用) 的首屏加载慢怎么解决?
- 代码分割 (SplitChunks)、路由懒加载。
- CDN 引入第三方库。
- Gzip 压缩。
- SSR (Nuxt.js) 或 预渲染。
- Vue 3 的
hoistStatic(静态提升) 是什么?- 编译器优化。将静态节点/属性提升到 render 函数之外,只创建一次,后续更新直接复用,不参与 Diff。
- 什么是 SSR?Vue 如何实现 SSR?
- 服务端渲染。使用
vue-server-renderer(Vue 2) 或 Vue 3 的 SSR API,通常配合 Nuxt.js 框架。
- 服务端渲染。使用
- 自定义指令 (Directive) 的钩子?
- Vue 2:
bind,inserted,update,componentUpdated,unbind. - Vue 3:
created,beforeMount,mounted,beforeUpdate,updated,beforeUnmount,unmounted.
- Vue 2:
- 如何解决 Vue 中的跨域问题?
- 开发环境:配置
vue.config.js/vite.config.js中的proxy(代理)。 - 生产环境:Nginx 反向代理或后端 CORS。
- 开发环境:配置
- assets 和 static (public) 目录的区别?
assets: 会被 Webpack/Vite 编译处理(压缩、Hash、Base64)。static/public: 不经过编译,直接拷贝到根目录。
- Vue 错误处理 (Error Handling)?
errorCaptured钩子 (组件内)。app.config.errorHandler(全局)。
- Vue 3 中的
defineAsyncComponent是什么?- 用于定义异步组件,支持加载状态、错误组件、超时设置等。
- 说一下 Vue 的 EventBus?
- Vue 2 中常用
new Vue()作为中央事件总线。Vue 3 移除了$on,$off,$emit实例方法,推荐使用 external 库 (如 mitt) 或全局状态管理。
- Vue 2 中常用