Vue2 面试题 200 题速记版
一、基础认知(1-15)
1. 什么是 Vue2?
- Vue2 是渐进式前端框架,核心能力是响应式数据绑定和组件化开发。
- 渐进式的意思是可以只用核心库,也可以逐步加路由、Vuex、工程化。
2. Vue2 的核心特性有哪些?
- 响应式:数据变,视图自动更新
- 组件化:页面拆成多个可复用模块
- 指令系统:如 v-if、v-for、v-model
- 虚拟 DOM:先比对 JS 层结构,再更新真实 DOM
- 单向数据流:父传子靠 props,子改父靠事件
- 生态完善:Vue Router、Vuex
3. Vue2 的优点是什么?
- 上手快
- 组件化开发效率高
- 数据驱动视图
- 虚拟 DOM 降低直接操作 DOM 成本
- 生态成熟
- 适合中后台和传统前端项目快速开发
4. MVC 和 MVVM 区别是什么?
- MVC:Model、View、Controller
- MVVM:Model、View、ViewModel
- Vue 属于 MVVM,ViewModel 就是 Vue 实例。
- Vue 实例负责把数据和视图关联起来。
5. Vue2 为什么适合做 SPA?
- 组件化 + 路由切换 + 状态管理,适合构建单页应用。
- SPA 只在首次加载时请求主页面,后续主要靠前端路由切换。
6. SPA 的优缺点是什么?
- 优点:页面切换快、交互流畅、前后端分离
- 缺点:首屏慢、SEO 差、首包大
- 所以 SPA 常配合懒加载、缓存、骨架屏优化体验。
7. Vue 实例从创建到销毁经历哪些阶段?
- 创建
- 挂载
- 更新
- 销毁
- 这是理解生命周期钩子的主线。
8. Vue 生命周期有哪些?
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
- keep-alive 组件还有 activated、deactivated
9. Vue2 和 jQuery 思路区别?
- jQuery 是手动操作 DOM
- Vue2 是数据驱动视图
- jQuery 更关注“怎么改 DOM”,Vue 更关注“数据变成什么”。
10. Vue2 和 React 的主要区别?
- Vue 偏模板语法
- React 偏 JS 表达 UI
- Vue2 响应式基于 defineProperty,React 主要依赖 setState 触发更新
- Vue 学习门槛通常更低,React 生态更偏函数式思维。
11. 什么是渐进式框架?
- 可以只用核心库,也可以逐步接入路由、状态管理、工程化。
- 不强制一开始就上全套。
12. Vue2 适合哪些项目?
- 中后台
- 管理系统
- 中小型 SPA
- 老项目维护
- 尤其适合已有 Vue2 存量项目。
13. Vue2 的缺点有哪些?
- 对新增属性和数组下标修改支持不直接
- 大型项目类型能力弱于现代方案
- 对老版本生态依赖较多
- 对复杂逻辑复用,mixin 可维护性一般。
14. 什么是声明式渲染?
- 只描述页面应该长什么样,具体 DOM 更新交给框架处理。
- 比如只写模板和数据,不自己手动增删 DOM。
15. 什么是数据驱动?
- 数据变,视图自动变,开发者少直接操作 DOM。
- 重点是“以数据为中心”,不是“以 DOM 为中心”。
二、生命周期(16-30)
16. created 和 mounted 区别?
- created:数据已初始化,DOM 还没挂载
- mounted:DOM 已挂载,可操作真实 DOM
- 所以请求一般放 created,操作 DOM 一般放 mounted。
17. 一般在哪个生命周期发请求?
- 常见在 created
- 需要操作 DOM 再请求时用 mounted
- 两者都能发请求,只是常见习惯不同。
18. 哪个生命周期适合操作 DOM?
- mounted
- 更新后拿最新 DOM 用 this.$nextTick
- 因为 mounted 之后真实节点已经生成。
19. 组件销毁前适合做什么?
- 清除定时器
- 解绑事件
- 销毁第三方实例
- 取消订阅
- 核心目的是防内存泄漏。
20. beforeUpdate 和 updated 区别?
- beforeUpdate:数据变了,DOM 还没更新
- updated:DOM 已完成更新
- 如果要拿更新后的 DOM,通常在 updated 或 nextTick 里处理。
21. beforeCreate 能拿到 data 吗?
- 不能,data、methods、watch 都还没初始化。
- 这个阶段主要是做实例初始化前的准备。
22. created 能操作 DOM 吗?
- 不适合,模板还没挂载到页面。
- 此时能拿到数据,拿不到最终渲染后的 DOM。
23. beforeMount 有什么用?
- 挂载前最后一步,此时模板已编译,但还没替换页面真实 DOM。
- 实战里用得不多,面试常问概念。
24. beforeDestroy 和 destroyed 区别?
- beforeDestroy:实例还可用
- destroyed:实例相关绑定基本已移除
- 清理副作用通常放 beforeDestroy 更稳妥。
25. keep-alive 相关生命周期有哪些?
- activated
- deactivated
- 只有被 keep-alive 缓存的组件才会触发。
26. activated 什么时候触发?
- 被 keep-alive 缓存的组件再次激活时触发。
- 常用于页面回来后刷新数据。
27. deactivated 什么时候触发?
- 被 keep-alive 缓存的组件切走时触发。
- 常用于暂停轮询、暂停定时器等。
28. 父子组件生命周期执行顺序?
- 挂载时一般是父 beforeCreate/created -> 父 beforeMount -> 子 beforeCreate/created/beforeMount/mounted -> 父 mounted。
- 面试常考“父先创建,子先挂载,最后父挂载完成”。
29. 更新阶段常见问题是什么?
- 不要在 updated 里继续改会触发更新的数据,容易死循环。
- updated 更适合做依赖 DOM 的收尾逻辑。
30. 销毁组件的方式有哪些?
- 条件渲染让组件卸载
- 路由切换
- this.$destroy(较少手动用)
- 实战里主要靠条件渲染和路由切换。
三、响应式原理(31-55)
31. Vue2 响应式原理是什么?
- 通过 Object.defineProperty 劫持对象属性的 getter/setter。
- 读取时收集依赖,修改时通知 watcher 更新。
- 简单说就是“读的时候记住谁用过,改的时候通知它们刷新”。
32. Vue2 为什么不用 Proxy?
- Vue2 诞生时要兼容较老浏览器,Proxy 兼容性差。
- Vue3 才全面转向 Proxy。
33. Vue2 怎么监听数组变化?
- 重写 push、pop、shift、unshift、splice、sort、reverse 等方法。
- 因为 defineProperty 不能直接拦截这些数组变异行为。
34. 为什么对象新增属性不是响应式?
- 因为 defineProperty 只能劫持已存在属性,后加属性没被劫持。
- 所以后加属性默认不会自动更新视图。
35. 怎么让新增属性变成响应式?
- 用 this.$set(obj, key, value) 或 Vue.set。
- 本质是手动补上响应式处理。
36. 为什么通过下标改数组不一定更新?
- 直接 arr[index] = value 无法被 Vue2 侦测。
- 应用 splice 或 this.$set(arr, index, value)。
- 因为 Vue2 主要拦截的是变异方法,不是数组索引赋值。
37. data 为什么必须是函数?
- 组件复用时如果 data 是对象,多个实例会共享同一份数据。
- 写成函数可保证每次返回独立对象。
- 根实例 new Vue 里的 data 可以是对象,组件里必须是函数。
38. 什么是依赖收集?
- 渲染时读取了哪些响应式数据,就把对应 watcher 收集起来,后续数据变更再触发更新。
- 谁在模板里用到了这个值,谁就是它的依赖。
39. watcher、dep、observer 分别是什么?
- observer:把数据变成响应式
- dep:依赖收集中心
- watcher:观察者,负责更新视图或执行回调
- 三者配合完成“收集依赖 + 通知更新”。
40. 什么是 Observer?
- 用来遍历对象/数组并把它们转成响应式数据的模块。
- 可以理解成响应式改造器。
41. 什么是 Dep?
- 每个响应式属性对应一个依赖管理器,负责收集和通知 watcher。
- 类似一个订阅列表。
42. 什么是 Watcher?
- 用于订阅数据变化,数据变更后执行更新函数。
- 常见有渲染 watcher、用户 watcher、计算属性 watcher。
43. 渲染 watcher 是什么?
- 组件渲染对应的 watcher,负责视图重新渲染。
- 页面更新本质上就是它在工作。
44. 用户 watcher 是什么?
- 开发者通过 watch 选项或 this.$watch 创建的 watcher。
- 主要用于监听变化后做副作用逻辑。
45. 计算属性 watcher 是什么?
- computed 内部也基于 watcher,默认带懒执行和缓存。
- 只有依赖变化且被访问时才重新计算。
46. 响应式更新为什么不是同步立刻更新 DOM?
- Vue 会把同一轮修改合并,异步批量更新更省性能。
- 否则多次 set 会导致多次无意义渲染。
47. Vue2 能监听对象删除属性吗?
- 不能直接监听普通 delete。
- 需要用 Vue.delete 或 this.$delete。
- 因为删除动作本身不会触发现有 setter。
48. Vue.set 原理大致是什么?
- 新增属性后手动做响应式处理,再通知依赖更新。
- 所以它不仅是赋值,还补了通知过程。
49. 数组方法为什么能触发更新?
- 因为 Vue2 重写了变异方法,方法执行后会手动通知更新。
- 比如 splice 后,Vue 知道数组内容发生了变化。
50. 为什么修改 length 可能不更新?
- length 变化不是被重写数组方法触发,Vue2 无法很好侦测。
- 所以不建议直接改 length 控制视图。
51. defineProperty 的缺点是什么?
- 不能直接监听新增/删除属性
- 不能直接监听数组下标和 length 变化
- 需要递归遍历对象,初始化成本较高
- 这也是 Vue3 改用 Proxy 的原因之一。
52. Vue2 响应式是深层的吗?
- 初始化时会递归处理已有嵌套对象,所以已有层级通常是深层响应式。
- 但前提是这些层级在初始化时就存在。
53. 为什么大对象初始化会变慢?
- 因为 Vue2 要递归遍历属性并逐个做 defineProperty 劫持。
- 数据层级越深、字段越多,初始化越重。
54. this.$watch 有什么用?
- 手动监听某个数据变化,适合动态注册监听逻辑。
- 比配置项 watch 更灵活。
55. this.$watch 返回什么?
- 返回一个取消监听的函数。
- 调用后就不再继续监听该数据。
四、模板与指令(56-80)
56. v-if 和 v-show 区别?
- v-if:控制是否渲染,切换时销毁/重建
- v-show:始终渲染,只切换 display
- 频繁切换用 v-show
- 很少切换、初始化成本高的逻辑可以考虑 v-if。
57. v-for 为什么必须加 key?
- 让 diff 更准确地识别节点身份,减少错误复用,提高更新效率。
- 没有 key 时,Vue 只能尽量就地复用节点。
58. key 为什么不建议用 index?
- 列表增删后 index 会变化,可能导致复用错位、状态错乱。
- 尤其表单项、动画列表更容易出问题。
59. v-model 原理是什么?
- 本质是 value + input 事件。
- 输入框值变化后触发事件更新数据。
- 也就是语法糖,不是魔法。
60. v-html 有什么风险?
- 有 XSS 风险,不能直接渲染不可信 HTML。
- 只适合渲染可信内容。
61. 常见 Vue 指令有哪些?
- v-bind:动态绑定属性
- v-on:绑定事件
- v-model:双向绑定表单
- v-if:条件渲染
- v-show:条件显示
- v-for:列表渲染
- v-text:设置纯文本
- v-html:插入 HTML
- v-once:只渲染一次
- v-pre:跳过编译
62. v-bind 的作用?
- 动态绑定 HTML 属性、class、style、组件 props。
- 简写是 :。
63. v-on 的作用?
- 绑定事件监听器。
- 简写是 @。
64. v-once 的作用?
- 只渲染一次,后续数据变化不再更新。
- 适合纯静态内容优化。
65. v-pre 的作用?
- 跳过该节点编译,加快编译速度。
- 常用于大段静态内容。
66. v-cloak 的作用?
- 配合 CSS 解决模板编译前插值闪烁问题。
- 本质是编译完成前先隐藏页面相关区域。
67. v-text 和插值表达式区别?
- v-text 会替换整个文本内容;插值更常用、更灵活。
- 插值写法是 {{}}。
68. 为什么 v-if 和 v-for 不建议写一起?
- 不建议写一起,因为列表遍历和条件判断耦合在一处,可读性和性能都一般。
- 更推荐先用 computed 过滤数据,再循环渲染。
- 面试里不要死记某个优先级版本细节,核心结论是“拆开写更好”。
69. template 标签有什么用?
- 作为逻辑包裹层,不会渲染成真实 DOM。
- 常配合 v-if、v-for 使用。
70. slot 是什么?
- 插槽,用于父组件向子组件指定内容分发位置。
- 可以理解成组件预留的“内容坑位”。
71. 具名插槽是什么?
- 给多个插槽起名字,父组件可定向传入内容。
- 解决一个组件有多个插槽位置的问题。
72. 作用域插槽是什么?
- 子组件把数据传给父组件插槽内容使用。
- 父组件决定渲染方式,子组件提供数据。
73. 为什么说作用域插槽可复用性高?
- 结构由子组件控制,内容渲染由父组件决定,灵活度更高。
- 常用于表格、列表、下拉框等组件封装。
74. 动态 class 怎么写?
- 可以写对象、数组或表达式。
- 对象适合条件类名,数组适合多个类组合。
75. 动态 style 怎么写?
- 可以绑定对象或对象数组。
- 对象 key 通常是 CSS 属性名。
76. 事件修饰符有哪些?
- .stop:阻止冒泡
- .prevent:阻止默认行为
- .capture:用捕获阶段监听
- .self:只在事件源是自己时触发
- .once:只触发一次
- .passive:告诉浏览器不会阻止默认行为,常用于滚动优化
77. 按键修饰符有哪些?
- enter、tab、delete、esc、space、up、down、left、right 等。
- 用来限制只有按下指定键时才触发事件。
78. 表单修饰符有哪些?
- .lazy:默认 v-model 多数表单会在 input 事件时同步;加上它后改成 change 时再同步,常见于失焦或确认后更新
- .number:把输入值尽量转成数字,避免得到字符串
- .trim:自动去掉输入首尾空格
- 这题面试很爱问具体含义,尤其是 .lazy。
79. 什么是自定义指令?
- 开发者自定义 DOM 行为复用逻辑的方式。
- 适合封装聚焦、拖拽、权限控制等直接操作 DOM 的场景。
80. 自定义指令常见钩子有哪些?
- bind:指令第一次绑定到元素时
- inserted:元素插入父节点时
- update:组件更新时
- componentUpdated:组件及子组件更新后
- unbind:指令解绑时
五、computed / watch / methods(81-95)
81. computed 和 watch 区别?
- computed:用于派生新值,有缓存
- watch:用于监听数据变化后执行副作用,可写异步逻辑
- 记忆方式:算结果用 computed,做事情用 watch。
82. computed 为什么有缓存?
- 依赖不变时直接返回上次结果,不重新执行 getter。
- 所以模板里多次使用同一计算属性不会重复算很多次。
83. watch 能监听对象内部变化吗?
- 能,但要配 deep: true。
- 因为默认只监听引用变化,不深挖内部层级。
84. watch 的 immediate 有什么用?
- 组件初始化时先执行一次回调。
- 相当于“先执行一次,再继续监听后续变化”。
85. methods 和 computed 区别?
- methods:每次调用都执行
- computed:依赖不变直接走缓存
- 模板里高频重复计算更适合 computed。
86. computed 能写 set 吗?
- 能,写成 getter/setter 形式即可。
- 这样既能读也能写,常见于 v-model 包装。
87. 什么场景用 computed?
- 模板中需要根据多个响应式数据推导新值。
- 比如全名拼接、列表过滤结果、状态文案。
88. 什么场景用 watch?
- 数据变化后发请求、做本地存储、处理异步逻辑。
- 它更像“监听后执行动作”。
89. watch 为什么适合异步?
- 因为它关注的是变化后的副作用,不要求必须同步返回值。
- 所以请求接口、延时处理都更适合放这里。
90. computed 为什么不适合异步?
- 计算属性本质用于同步返回计算结果,异步会破坏依赖追踪与使用体验。
- 面试答法:computed 要的是“值”,watch 要的是“过程”。
91. 多个数据组合计算该用什么?
- 优先用 computed。
- 因为它语义更对,也有缓存。
92. 监听路由变化怎么做?
- watch $route 或使用路由守卫。
- 简单监听用 watch,页面进出控制常用守卫。
93. watch 写函数和对象形式区别?
- 对象形式可配置 handler、deep、immediate。
- 所以对象形式功能更全。
94. 什么是侦听属性?
- 就是 watch,用来观察某个数据的变化。
- 变化后通常执行副作用,而不是返回值。
95. 计算属性依赖没变会重新执行吗?
- 不会,会直接读缓存结果。
- 这是 computed 相比 methods 的关键优势。
六、异步更新与 nextTick(96-105)
96. Vue2 为什么是异步更新?
- 同一轮事件循环内多次改数据会合并更新,减少重复渲染,提高性能。
- 这叫批量异步更新策略。
97. nextTick 是什么?
- 在下次 DOM 更新完成后执行回调。
- 常用于“改完数据,立刻拿最新 DOM”。
98. nextTick 的使用场景?
- 改完数据后立刻拿最新 DOM
- 处理滚动、聚焦、尺寸计算
- 总之是依赖“更新后 DOM”的场景。
99. nextTick 原理是什么?
- 优先用微任务,如 Promise、MutationObserver;降级再用宏任务。
- 核心目的是把回调放到 DOM 更新后再执行。
100. 数据改了为什么拿到的 DOM 还是旧的?
- 因为 DOM 更新是异步批量执行的,需要等 nextTick。
- 改数据成功不等于 DOM 立刻同步完成。
101. Vue 的异步队列是什么?
- Vue 会把同一轮数据变更对应的 watcher 放进队列,去重后统一刷新。
- 这样能避免重复更新同一个组件。
102. watcher 为什么要去重?
- 避免同一 watcher 重复入队,多次无效渲染。
- 一句话:防重复刷新。
103. nextTick 一定是微任务吗?
- 优先微任务,不行再降级到宏任务。
- 所以不能绝对说它永远是微任务。
104. this.$nextTick 和 Vue.nextTick 区别?
- 本质类似,this.$nextTick 更常在组件实例里使用。
- 写在组件里通常直接用 this.$nextTick。
105. 什么情况下不需要 nextTick?
- 不依赖更新后 DOM,只关心数据本身时不需要。
- 比如只是继续处理 JS 数据,不读界面节点。
七、组件通信(106-120)
106. 组件通信方式有哪些?
- 父传子:props
- 子传父:$emit
- 父拿子:ref
- 跨层级:provide/inject
- 任意组件:EventBus
- 全局状态:Vuex
- 面试通常先答这 6 类就够了。
107. 父子组件传值怎么做?
- 父传子用 props
- 子传父用 $emit
- 这是最基本、最规范的通信方式。
108. 兄弟组件通信怎么做?
- 通过共同父组件中转
- 或 EventBus
- 复杂项目一般用 Vuex
- 推荐优先选更清晰、可维护的方式。
109. 为什么不推荐直接改 props?
- props 是单向下行绑定,子组件直接改会破坏数据流。
- Vue 也会给出警告。
110. .sync 语法糖是什么?
- 本质是父传值 + 子触发 update:xxx 事件。
- 只是把这套写法简化了。
111. ref 有什么用?
- 获取组件实例或 DOM 节点。
- 常用于调用子组件方法或拿原生节点。
112. $children 和 ref 区别?
- ref 更明确可控,$children 顺序不稳定且不推荐依赖。
- 实战优先用 ref。
113. provide/inject 适合什么场景?
- 跨多层组件传递依赖或配置,避免层层 props。
- 常用于组件库或祖孙组件通信。
114. EventBus 原理是什么?
- 通过统一事件中心做发布订阅。
- 一个组件 emit,另一个组件 on 接收。
115. EventBus 有什么问题?
- 事件来源不清晰、难维护、容易忘记解绑。
- 项目一大就容易混乱。
116. 父组件如何调用子组件方法?
- 通过 ref 获取子组件实例再调用。
- 比如 this.$refs.child.xxx()。
117. 子组件如何通知父组件?
- this.$emit(‘事件名’, 参数)
- 父组件监听这个自定义事件。
118. 非父子组件通信推荐什么?
- 简单场景 EventBus,复杂共享状态更推荐 Vuex。
- 面试答法要体现“场景区分”。
119. props 校验怎么做?
- 用 type、required、default、validator 做约束。
- 这样组件接口更清晰,也更不容易误用。
120. props 为什么默认工厂函数返回对象?
- 避免多个组件实例共享同一引用类型默认值。
- 跟 data 写成函数是同一类思路。
八、组件化与复用(121-130)
121. 组件是什么?
- 可复用、可维护、独立封装的 UI 单元。
- 本质是把页面拆成更小的职责模块。
122. 组件化有什么好处?
- 提高复用性
- 降低耦合
- 方便维护和协作
- 也是大型前端项目的基础。
123. Vue 组件由哪几部分组成?
- template
- script
- style
- 分别对应结构、逻辑、样式。
124. 单文件组件是什么?
- 把模板、逻辑、样式写在一个 .vue 文件中。
- 这是 Vue 项目最常见的组件组织形式。
125. mixin 是什么?
- 多组件复用逻辑的一种机制,会把配置合并到组件里。
- 常用于复用 data、methods、生命周期等。
126. mixin 的缺点是什么?
- 来源不直观、命名冲突、依赖关系隐式。
- 所以复杂项目里维护成本会变高。
127. extends 和 mixin 区别?
- extends 更像单继承扩展,mixin 是混入多个配置。
- mixin 更灵活,但冲突概率也更高。
128. keep-alive 有什么用?
- 缓存组件实例,切换回来不重新创建。
- 常用于列表页返回保留滚动和表单状态。
129. keep-alive 常用属性有哪些?
- include:只缓存指定组件
- exclude:排除指定组件
- max:限制最大缓存数量
- 控制缓存范围,避免无限缓存。
130. 异步组件是什么?
- 按需加载组件,减少首屏包体积。
- 只有用到时才去加载对应组件代码。
九、虚拟 DOM 与 diff(131-140)
131. 什么是虚拟 DOM?
- 用 JS 对象描述真实 DOM 结构。
- 它不是页面节点本身,而是页面结构的抽象表示。
132. 为什么要有虚拟 DOM?
- 方便用 JS 描述 UI,结合 diff 减少直接操作真实 DOM 的成本。
- 它更像框架更新视图的中间层。
133. diff 算法的作用是什么?
- 比较新旧虚拟 DOM,找出最小更新范围。
- 核心目标是少改真实 DOM。
134. Vue2 的 diff 是全量比较吗?
- 不是,通常是同层比较,不做跨层级暴力比较。
- 这样复杂度更可控。
135. 为什么 key 能优化 diff?
- 帮助快速识别节点身份,减少错误复用和无效移动。
- 没 key 或 key 不稳定时,列表更新更容易出错。
136. patch 是什么?
- 把虚拟 DOM 的差异应用到真实 DOM 的过程。
- diff 找差异,patch 负责真正更新。
137. Vue2 更新列表时为什么要避免频繁重排?
- 真实 DOM 重排重绘成本高,diff 目标就是减少这种成本。
- 所以列表优化本质是在减少真实节点操作。
138. 虚拟 DOM 一定比真实 DOM 快吗?
- 不一定。简单场景直接操作 DOM 可能更快,但框架整体维护成本更低。
- 面试不要绝对化回答“虚拟 DOM 一定更快”。
139. 为什么说模板最终会变成 render?
- 模板会先编译成 render 函数,再生成虚拟 DOM。
- 所以模板语法本质上最终都会变成 JS 渲染逻辑。
140. render 函数的作用是什么?
- 用 JS 描述组件应该渲染成什么样。
- 它返回的是虚拟 DOM 结构。
十、路由(141-155)
141. Vue Router 的两种模式是什么?
- hash
- history
- 区别核心在 URL 形式和服务端支持要求。
142. hash 和 history 区别?
- hash 带 #,不依赖服务端配置
- history URL 更美观,但刷新需要服务端兜底到 index.html
- 所以 history 更好看,但部署要求更高。
143. route 和 router 区别?
- $route:当前路由信息对象
- $router:路由实例,负责跳转等操作
- 记忆:一个是“当前信息”,一个是“操作工具”。
144. 路由传参有哪些方式?
- params
- query
- 动态路由 + params
- 实战中 query 更常见,params 更适合路径语义。
145. 导航守卫有哪些?
- 全局守卫:beforeEach、beforeResolve、afterEach
- 路由独享守卫
- 组件内守卫
- 常用于权限、登录、离开确认。
146. beforeEach 常用来做什么?
- 登录校验、权限控制、埋点、页面标题处理。
- 它是最常用的全局前置守卫。
147. params 和 query 区别?
- params 更像路径参数
- query 更像 URL 查询参数
- query 通常会直接显示在 ? 后面。
148. 编程式导航怎么写?
- this.$router.push、replace、go。
- 就是用 JS 主动控制路由跳转。
149. push 和 replace 区别?
- push 会新增历史记录
- replace 会替换当前记录
- 所以 replace 后点返回可能回不到当前页。
150. 路由懒加载怎么做?
- 组件写成动态 import。
- 本质是代码分包,访问到该路由再加载。
151. 什么是嵌套路由?
- 在父路由下继续配置 children 渲染子页面。
- 常用于布局页 + 内容区结构。
152. 什么是动态路由?
- 路由路径中带变量参数,如 /user/:id。
- 适合详情页、用户页这类路径模式固定但参数变化的场景。
153. 组件内路由守卫有哪些?
- beforeRouteEnter
- beforeRouteUpdate
- beforeRouteLeave
- 分别对应进入、复用更新、离开。
154. beforeRouteLeave 常见用途?
- 页面离开前确认、表单未保存提示。
- 很典型的拦截离开场景。
155. history 模式刷新 404 怎么办?
- 服务端统一回退到 index.html。
- 因为前端路由地址需要交还给前端应用处理。
十一、Vuex(156-170)
156. Vuex 是什么?
- Vue 官方状态管理库,用于集中管理共享状态。
- 适合多个组件依赖同一份状态的场景。
157. Vuex 的核心概念有哪些?
- state:状态
- getters:派生状态
- mutations:同步修改状态
- actions:异步操作
- modules:模块化拆分
- 这五个是面试必答核心。
158. mutations 和 actions 区别?
- mutations:必须同步,直接改 state
- actions:可异步,最终通过 commit 调 mutations
- 记忆:mutation 改值,action 处理流程。
159. 为什么 mutations 必须同步?
- 方便 devtools 追踪状态变化,保证变更可预测。
- 如果异步,调试时难以定位状态何时变化。
160. getters 有什么用?
- 对 state 做派生计算,类似 store 的 computed。
- 不直接存新状态,而是基于已有状态算结果。
161. commit 和 dispatch 区别?
- commit 触发 mutations
- dispatch 触发 actions
- 一个偏同步提交,一个偏流程调度。
162. modules 有什么用?
- 把大型 store 按业务拆分,降低维护成本。
- 避免所有状态都堆在一个文件里。
163. 命名空间 namespaced 有什么用?
- 避免模块间方法名、getter 名冲突。
- 大项目里基本都会用到。
164. Vuex 持久化怎么做?
- 常配合 localStorage/sessionStorage 或插件做持久化。
- 因为 Vuex 默认只存在内存里。
165. 页面刷新后 Vuex 数据为什么没了?
- Vuex 默认是内存状态,刷新页面会重新初始化。
- 所以需要持久化方案补上。
166. 什么时候不需要 Vuex?
- 组件层级浅、共享状态少时没必要上全局状态管理。
- 否则反而增加复杂度。
167. Vuex 和 EventBus 区别?
- Vuex 更规范、可追踪;EventBus 更轻但不易维护。
- 项目规模越大,越能体现 Vuex 的优势。
168. mapState、mapGetters 有什么用?
- 快速把 store 中状态和 getter 映射到组件计算属性。
- 减少重复样板代码。
169. mapMutations、mapActions 有什么用?
- 快速把 mutations、actions 映射为组件方法。
- 让组件里调用 store 更简洁。
170. 严格模式 strict 有什么作用?
- 监控是否在 mutation 之外修改 state。
- 开发阶段排查问题很有用,生产一般不常开。
十二、性能优化(171-180)
171. Vue2 常见性能优化手段有哪些?
- 路由懒加载
- 组件按需加载
- v-if/v-show 合理使用
- keep-alive
- 防抖节流
- 长列表优化
- 核心思路就是减少首屏体积和减少无效渲染。
172. 为什么不要滥用 deep watch?
- 深度遍历成本高,数据大时性能差。
- 只有确实需要监听深层变化时再开。
173. 为什么不要在模板里写复杂表达式?
- 可读性差,重复执行成本更高。
- 复杂逻辑更适合放 computed 或 methods。
174. 长列表怎么优化?
- 分页
- 虚拟列表
- 避免无意义重渲染
- 本质是减少同时存在的 DOM 数量。
175. 为什么 key 要稳定?
- 稳定 key 能减少错误复用和不必要更新。
- 不稳定 key 会让 diff 判断失真。
176. computed 为什么常能优化性能?
- 有缓存,避免模板中重复计算。
- 同样依赖不变时不会反复执行。
177. 事件销毁不及时会怎样?
- 内存泄漏、重复触发、页面越来越卡。
- 常见于 window 事件、总线事件、定时器没清理。
178. keep-alive 是不是越多越好?
- 不是,缓存过多会增加内存占用。
- 只缓存真正需要保留状态的页面。
179. 异步组件为什么能优化首屏?
- 把非首屏组件拆出去,减少首包体积。
- 首次只加载当前必要资源。
180. 图片很多时怎么优化?
- 懒加载、压缩、合理尺寸、CDN。
- 图片问题本质是请求量和资源体积问题。
十三、工程化与实践(181-190)
181. Vue CLI 是什么?
- Vue 官方脚手架,用于快速初始化 Vue2 工程。
- 帮你生成基础目录、配置和开发环境。
182. .vue 文件怎么被浏览器识别?
- 先经过构建工具和 vue-loader 编译,再打包成浏览器可运行代码。
- 浏览器本身并不认识 .vue 文件。
183. scoped 原理是什么?
- 给当前组件元素和样式加特定属性选择器,限制样式作用范围。
- 常见表现是元素上多一个 data-v-xxx。
184. scoped 一定能完全隔离样式吗?
- 不能,子组件根元素、深度选择器等场景仍需注意。
- 所以 scoped 不是绝对隔离。
185. 深度选择器怎么写?
- 常见写法有 ::v-deep、/deep/、>>>,取决于构建环境。
- 用于穿透 scoped 影响子组件内部样式。
186. CSS Module 和 scoped 区别?
- scoped 是样式作用域限制,CSS Module 是类名局部化。
- 两者目标类似,但实现思路不同。
187. 环境变量有什么用?
- 区分开发、测试、生产环境配置。
- 比如接口地址、开关配置通常都靠它区分。
188. 为什么前端要做按需加载?
- 降低首屏资源体积,提升加载速度。
- 不常用代码没必要一开始就全下到浏览器。
189. 什么是 source map?
- 把打包后代码映射回源码,方便调试。
- 这样报错时更容易定位到原始代码位置。
190. 生产环境为什么常关掉 source map?
- 减少源码暴露和构建体积压力。
- 也能降低被逆向分析的风险。
十四、常见场景题(191-200)
191. 登录权限一般怎么做?
- 路由守卫拦截 + token 校验 + 角色权限控制。
- 常见流程是登录后存 token,进路由前判断权限。
192. 页面刷新后如何保留登录态?
- token 存 localStorage/cookie,初始化时再恢复用户信息。
- 只存 Vuex 不够,因为刷新会丢。
193. 列表页切详情再返回怎么保留状态?
- keep-alive、路由缓存、状态持久化。
- 常见要保留滚动位置、筛选条件、分页状态。
194. 表单重复提交怎么处理?
- 按钮禁用、loading、防抖节流。
- 核心是限制重复触发提交逻辑。
195. 请求取消怎么做?
- 常见用 axios 取消机制或组件销毁时中断请求。
- 避免页面已销毁但请求回来还更新数据。
196. 如何统一处理接口错误?
- 在请求拦截器/响应拦截器统一处理。
- 这样错误提示、登录过期处理都能收口。
197. 如何封装公共组件?
- 明确输入输出:props、events、slots,保证低耦合和可复用。
- 组件接口越清晰,复用越稳定。
198. 如何做页面级缓存?
- keep-alive + 路由元信息 + 缓存名单控制。
- 不是所有页面都缓存,要按场景控制。
199. 如何避免内存泄漏?
- 销毁定时器、解绑监听、清理订阅、释放第三方实例。
- 面试答这题一定要提“副作用清理”。
200. 中后台项目 Vue2 面试最常问什么?
- 生命周期
- 响应式原理
- computed/watch
- nextTick
- 组件通信
- 路由守卫
- Vuex
- 这些基本就是 Vue2 面试主线。
高频补充
- 核心主线:响应式 -> 模板编译 -> 虚拟 DOM -> diff -> 组件更新
- 高频对比:computed/watch、v-if/v-show、hash/history、route/router、action/mutation
- 高频陷阱:对象新增属性、数组下标修改、key 用 index、props 直接修改、updated 死循环
- 高频场景:nextTick、$set、keep-alive、权限路由、状态持久化、长列表优化