Vue相关面试题

Vue 面试题(2026高频版):基础+进阶+手写+项目实战

结合最新面试趋势,整理了分梯度、带答题思路、附手写代码的Vue核心面试题,覆盖入门到资深级考点,帮你快速抓住重点、高效备考。

一、基础必懂(入门级,80%面试会问)

1. Vue 中 data 为什么是函数而不是对象?

核心答案

  • 组件是可复用的实例,若data是对象,所有组件实例会共享同一个data对象,导致数据互相污染;
  • 若data是函数,每次创建组件实例时会执行函数,返回全新的data对象,保证每个实例数据独立。
    补充:根实例(new Vue({ data: {} }))的data可以是对象,因为根实例只会创建一次,不存在复用问题。

2. 简述 Vue 的双向绑定原理(v-model 底层)

核心答案

  • v-model 是语法糖,本质是 v-bind:value + v-on:input
  • 原生表单元素:<input v-model="val"> 等价于 <input :value="val" @input="val = $event.target.value">
  • 自定义组件:父组件通过 v-model 绑定,子组件接收 modelValue prop,触发 update:modelValue 事件实现双向绑定。
    手写示例(自定义组件v-model)
vue 复制代码
<!-- 子组件 MyInput.vue -->
<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
</template>
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

<!-- 父组件使用 -->
<MyInput v-model="username" />

3. computed 和 watch 的核心区别及使用场景

维度 computed watch
本质 计算属性,依赖其他数据返回新值 监听器,监听数据变化执行逻辑
缓存 有缓存(依赖不变则复用结果) 无缓存,数据变就触发
同步/异步 仅支持同步 支持同步+异步(如请求接口)
使用场景 数据推导(如拼接姓名、格式化金额) 数据变化触发异步操作(如搜索防抖、联动请求)

示例

javascript 复制代码
// computed:姓名拼接(同步、缓存)
const fullName = computed(() => `${firstName.value} ${lastName.value}`)

// watch:搜索防抖(异步)
watch(searchKey, (newVal) => {
  const timer = setTimeout(() => {
    // 发起搜索请求
  }, 300)
  return () => clearTimeout(timer) // 清除防抖定时器
}, { immediate: true }) // 立即执行一次

4. v-if 和 v-show 的区别及选型依据

维度 v-if v-show
渲染逻辑 条件假时移除DOM节点 条件假时隐藏(display:none)
切换开销 高(销毁/重建组件) 低(仅切换样式)
初始渲染 条件假时不渲染 无论条件都渲染
适用场景 条件少变(如权限控制、页面Tab) 条件频繁切换(如弹窗、下拉菜单)

二、进阶核心(中级,区分度考点)

1. Vue2 和 Vue3 响应式原理的核心差异

维度 Vue2 Vue3
核心API Object.defineProperty Proxy + Reflect
监听范围 仅监听对象属性(需遍历) 监听整个对象
数组支持 重写数组方法(push/pop等) 原生支持数组索引/长度变化
新增属性 需 Vue.set 手动监听 自动监听新增/删除属性
复杂类型 不支持Map/Set 支持Map/Set/WeakMap等

Vue3响应式手写简化版

javascript 复制代码
function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      // 依赖收集(简化版)
      track(target, key)
      return Reflect.get(target, key)
    },
    set(target, key, value) {
      const result = Reflect.set(target, key, value)
      // 派发更新(简化版)
      trigger(target, key)
      return result
    }
  })
}

2. 虚拟DOM(VNode)的核心作用及diff算法逻辑

虚拟DOM :用JS对象描述DOM结构(如 { tag: 'div', props: { id: 'box' }, children: [] }),避免直接操作真实DOM。
diff算法核心原则

  1. 同层比较,不跨层级(如根节点div不会和子节点p比较);
  2. 列表对比依赖key:用key唯一标识节点,避免就地复用导致数据错乱;
  3. Vue3优化:PatchFlags标记静态节点,跳过无变化节点的对比,提升diff效率。

关键考点:v-for为什么必须加key?

  • 不加key:Vue会就地复用节点(如列表排序后,仅更新内容不移动DOM),导致表单值错乱、动画异常;
  • 禁止用index做key:列表顺序变化时index也会变,失去唯一标识作用,推荐用后端返回的唯一ID。

3. Vue Router 两种模式(hash/history)的区别及部署问题

维度 hash模式 history模式
URL特征 带#(如/#/home) 无#(如/home)
底层原理 基于hashchange事件 基于HTML5 History API
兼容性 兼容所有浏览器 需IE10+
部署要求 无需后端配置 需后端配置(刷新404)

history模式部署解决(Nginx配置)

nginx 复制代码
server {
  location / {
    try_files $uri $uri/ /index.html; # 所有请求转发到index.html
  }
}

4. Pinia 对比 Vuex 的核心优势(Vue3主流)

维度 Vuex Pinia
核心概念 State/Mutation/Action/Module State/Action/Getter(无Mutation)
模块化 嵌套Module,命名空间复杂 每个Store独立,天然模块化
TS支持 需手动定义类型 原生支持TS,类型推断完善
数据修改 必须通过Mutation(同步) 直接修改State(同步/异步)
体积 较大 更小,支持Tree-Shaking

Pinia使用示例

javascript 复制代码
// stores/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
  state: () => ({ name: '张三', age: 20 }),
  getters: {
    fullInfo: (state) => `${state.name}(${state.age}岁)`
  },
  actions: {
    async updateName(newName) {
      // 异步请求接口
      await api.updateUser({ name: newName })
      this.name = newName // 直接修改state
    }
  }
})

// 组件中使用
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
userStore.updateName('李四')

三、高级实战(资深级,项目经验考点)

1. Vue 项目性能优化的核心手段(分维度)

(1)代码层面
  • 响应式优化:Vue3用shallowReactive(浅响应)/markRaw(非响应式)减少监听开销;
  • 渲染优化:避免模板复杂表达式,用computed缓存结果;v-for和v-if不混用(v-if放外层);
  • 事件优化:自定义事件及时解绑,滚动/输入事件加节流防抖。
(2)组件层面
  • 异步组件:defineAsyncComponent拆分大组件,按需加载;
  • 组件缓存:keep-alive缓存频繁切换的组件(如Tab页),减少重复渲染;
  • 长列表优化:虚拟滚动(vue-virtual-scroller),只渲染可视区域。

异步组件示例

vue 复制代码
<script setup>
import { defineAsyncComponent } from 'vue'
// 按需加载弹窗组件
const Dialog = defineAsyncComponent(() => import('./Dialog.vue'))
</script>
(3)打包层面
  • 路由懒加载:const Home = () => import('./Home.vue')
  • 第三方库按需引入:如Element Plus只引入需要的组件;
  • CDN引入:Vue、Pinia等库通过CDN引入,减少打包体积。

2. Composition API 对比 Options API 的优势

维度 Options API Composition API
逻辑组织 按选项分散(data/methods) 按功能聚合(如登录逻辑放一起)
逻辑复用 mixins(命名冲突、来源不明) Composables(组合函数,清晰复用)
TS支持 差,需额外配置 原生支持,类型推断完善
灵活性 低,受选项约束 高,按需组合逻辑

Composables复用示例(useRequest.js)

javascript 复制代码
// composables/useRequest.js
import { ref } from 'vue'
export function useRequest(api) {
  const data = ref(null)
  const loading = ref(false)
  const error = ref(null)
  
  const fetchData = async () => {
    loading.value = true
    try {
      data.value = await api()
    } catch (e) {
      error.value = e
    } finally {
      loading.value = false
    }
  }
  
  return { data, loading, error, fetchData }
}

// 组件中复用
import { useRequest } from '@/composables/useRequest'
const { data, loading, fetchData } = useRequest(api.getUserList)
fetchData()

3. Vue 项目中如何处理跨域问题

(1)开发环境(本地调试)
  • 配置代理(Vite示例):
javascript 复制代码
// vite.config.js
export default {
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000', // 后端接口地址
        changeOrigin: true, // 开启跨域
        rewrite: (path) => path.replace(/^\/api/, '') // 去掉/api前缀
      }
    }
  }
}
(2)生产环境
  • 后端配置CORS:设置Access-Control-Allow-Origin为前端域名;
  • Nginx反向代理:将前端请求转发到后端,避免跨域。

四、手写题(高频压轴)

1. 实现 Vue 简易响应式(Vue3 思路)

javascript 复制代码
// 依赖收集容器
const targetMap = new WeakMap()
let activeEffect = null

// 依赖收集
function track(target, key) {
  if (!activeEffect) return
  let depsMap = targetMap.get(target)
  if (!depsMap) targetMap.set(target, (depsMap = new Map()))
  let deps = depsMap.get(key)
  if (!deps) depsMap.set(key, (deps = new Set()))
  deps.add(activeEffect)
}

// 派发更新
function trigger(target, key) {
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  const deps = depsMap.get(key)
  if (deps) deps.forEach(effect => effect())
}

// 响应式核心
function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      track(target, key)
      return Reflect.get(target, key)
    },
    set(target, key, value) {
      const result = Reflect.set(target, key, value)
      trigger(target, key)
      return result
    }
  })
}

// 副作用函数
function effect(fn) {
  activeEffect = fn
  fn() // 执行一次,触发依赖收集
  activeEffect = null
}

// 测试
const state = reactive({ count: 0 })
effect(() => {
  console.log('count:', state.count) // 初始执行,count变化时重新执行
})
state.count = 1 // 触发更新,打印count:1

2. 实现自定义指令 v-debounce(防抖)

vue 复制代码
<script setup>
// 注册全局自定义指令
import { app } from '@/main'
app.directive('debounce', {
  mounted(el, binding) {
    const [fn, delay = 300] = binding.value
    let timer = null
    el.addEventListener('click', () => {
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => fn(), delay)
    })
  }
})

// 组件中使用
const handleSearch = () => {
  console.log('搜索')
}
</script>

<template>
  <button v-debounce="[handleSearch, 500]">搜索</button>
</template>

总结

核心考点回顾

  1. 基础层:data函数原因、v-model原理、computed/watch、v-if/v-show;
  2. 进阶层:响应式原理、虚拟DOM/diff、路由模式、Pinia vs Vuex;
  3. 实战层:性能优化、Composition API、跨域处理、手写代码。

答题技巧

  • 基础题:先答核心逻辑,再补示例;
  • 进阶题:结合原理+项目场景(如diff算法说key的实际坑);
  • 手写题:先讲思路,再写核心代码,最后补边界处理。
相关推荐
TON_G-T3 小时前
前端包管理器(npm、yarn、pnpm)
前端
卤炖阑尾炎3 小时前
Web 技术基础与 Nginx 网站环境部署全解析
前端·nginx·microsoft
oo121383 小时前
里程碑4 - 基于Vue3完成动态组件库建设
前端
好名字08213 小时前
Vue2转Word方法(html-docx-js库)
javascript·html·word
火车叼位3 小时前
告别表单“黄油色”:如何优雅地重置 Chrome 自动填充样式
前端
Dragon Wu3 小时前
Taro Webpack 5 编译过慢的解决方案
前端·webpack·小程序·taro
认真学GIS3 小时前
日尺度地下水水位!全国11897个地下水动态监测站点2005-2021年日尺度地下水水位(地下水埋深)(EXCEL格式)数据
服务器·前端·excel
_DoubleL3 小时前
Volta启动项目自动切换Node版本
前端·node.js
阿里巴巴终端技术3 小时前
[第 20 届 D2 倒计时] 7 大专场演讲、44 个精彩话题、D2 之夜畅聊 AI + 终端的发展前景
前端·人工智能·程序员