Skip to content

Vue 面试基础:高频 8 题(偏初级) ​

这个小模块主要帮我快速过一遍 最常见的 Vue 面试题,不卷源码,重点是会用 + 讲得清楚。


一、Vue 高频基础题总表 ​

  1. Vue 的响应式原理大概是怎么实现的?(2.x / 3.x)
  2. v-if 和 v-show 有什么区别?实际开发怎么选?
  3. computed 和 watch 有什么区别?分别适合什么场景?
  4. 父子组件是如何通信的?常见几种方式?
  5. v-model 本质是什么?在组件里怎么自定义 v-model?
  6. 在列表渲染中为什么一定要加 key?用索引当 key 有什么问题?
  7. axios 请求一般放在哪一层?怎么统一处理错误、loading、token?
  8. 前端路由的 hash 模式 和 history 模式 有什么区别?配合后端要注意什么?

建议:先保证这 8 题你都能用自己的话讲 2~3 分钟,再去看更细的语法和生态。


二、高频问题示例答案(简版) ​

1. Vue 的响应式原理大概是怎么实现的? ​

简短版本(适合初级面试):

  • Vue 2.x 主要是通过 Object.defineProperty 监听数据的 get/set,在 set 的时候触发视图更新。
  • Vue 3.x 则是用 Proxy 做数据劫持,可以完美监听新增/删除属性、数组下标等问题,弥补了 2.x 的一些缺陷。

可以顺带提一句:

  • 模板里用到的数据,会在依赖收集阶段记录下来,数据变更时,只有依赖了它的那部分组件会重新渲染,而不是整棵树全部刷新。

2. v-if 和 v-show 有什么区别?怎么选? ​

  • v-if:条件为 false 时,组件/DOM 直接不会渲染 或被销毁;为 true 时才真正创建。适合很少切换的场景,比如权限控制、大模块的按需渲染。
  • v-show:始终会渲染到 DOM,只是通过 display: none 控制显示/隐藏。适合频繁切换的场景,比如 tab 切换、小弹窗。

一句话记忆:“频繁切换用 v-show,偶尔切换用 v-if”。


3. computed 和 watch 有什么区别? ​

  • computed(计算属性):

    • 依赖其它响应式数据,有缓存。
    • 只有当依赖的数据发生变化时才会重新计算。
    • 适合从已有数据中 派生出新数据(比如:全名、过滤后的列表)。
  • watch(侦听器):

    • 监听某个数据的变化,在变化时执行副作用逻辑。
    • 适合处理异步请求、手动控制逻辑(例如根据输入框内容去搜索接口)。

一句话区分:“需要一个新值用 computed,要在值变化时做事用 watch”。


4. 父子组件如何通信?(最常用的几种) ​

  • 父传子:通过 props 传值。
  • 子通知父:通过 $emit 触发自定义事件,父组件在模板上监听。
  • 兄弟组件/跨多层:可以用 全局事件总线 / Vuex / Pinia / provide/inject 等方式(初级面试会提到名字即可)。

面试时可以举一个简单例子:父组件把列表数据传给子组件展示,子组件点击“删除”按钮,通过 $emit('delete', id) 通知父组件真正去删数据。


5. v-model 本质是什么?组件里怎么自定义? ​

  • 在原生表单元素上,v-model 大概相当于:
    html
    <input :value="msg" @input="msg = $event.target.value" />
  • 在组件上,Vue 3 里等价于:
    vue
    <Child v-model="value" />
    <!-- 等价于 -->
    <Child :modelValue="value" @update:modelValue="value = $event" />
  • 自定义组件想支持 v-model,只需要:
    • 接收一个 modelValue 的 prop。
    • 在内部通过 emit('update:modelValue', newVal) 往外抛。

6. 为啥列表渲染一定要加 key?索引用作 key 有什么问题? ​

  • key 的主要作用是 帮助虚拟 DOM 更准确地复用元素。
  • 如果不加 key 或用索引当 key,在插入/删除中间某一项时,可能会导致:
    • 复用错误的 DOM 节点。
    • 比如输入框错位、动画异常、组件内部状态混乱。
  • 通常建议用 唯一业务 id 作为 key。

7. axios 一般怎么用?放在哪一层? ​

  • 一般会抽一层 统一的请求封装:
    • 统一设置 baseURL、超时时间。
    • 请求拦截里加上 token。
    • 响应拦截统一处理错误提示、登录失效跳转等。
  • 页面或组件里只调用 封装好的 API 函数,例如:
    ts
    import { getUserList } from '@/api/user'
    const list = await getUserList()

面试时可以简单描述你项目里的封装结构,哪怕是自己练手项目也可以讲清楚“为什么要这么封、怎么封”的思路。


8. 前端路由 hash 模式 vs history 模式 有什么区别? ​

  • hash 模式:URL 里带 #,如 /#/home,后端只会看到 /# 前面的部分;刷新不会 404,部署最简单。
  • history 模式:URL 更干净,如 /home,需要后端配合 把所有路径都返回同一个 index.html,否则刷新会 404。

对于面试官常问的“你们项目用的什么模式、为什么”,可以回答:

  • 管理后台项目一般会选 history 模式,URL 更好看,但需要 nginx 做 try_files 配置。
  • 如果是纯静态托管环境、后端配合不好,hash 模式更省事。