Vue2 面试题 200 题速记版

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、权限路由、状态持久化、长列表优化