前端面试题之Vue3篇

370 阅读7分钟

1. 简述 Vue3 相比 Vue2 有哪些主要改进

1. 性能优化
  • 更快的虚拟 DOM:Vue3 的虚拟 DOM 重写,diff 算法更高效。

  • 编译优化:静态提升、事件缓存、内联缓存等,让运行时更快。

  • 体积更小:源码用 TypeScript 重写,按需 Tree-shaking,最小构建比 Vue2 小约 40%。

2. Composition API
  • 新增 setup() :可以在一个函数里集中管理逻辑。

  • reactive / ref / computed / watch 等独立 API,更灵活、更易复用。

  • 逻辑复用不再依赖 mixins,更清晰、更可维护。

例如 Vue2 用 data + methods 分散逻辑,Vue3 可以用 Composition API 把同一逻辑写在一起。

3. 更好的 TypeScript 支持
  • Vue3 源码完全用 TypeScript 重写。

  • API 类型提示更友好,开发时更容易发现问题。

4. 新的组件功能
  • Teleport:允许把组件渲染到 DOM 的任意位置。

  • Suspense:支持异步组件的加载占位和 fallback UI。

  • Fragment:支持组件返回多个根节点,不必强制包裹一个 <div>

  • emits 选项:显式声明组件事件,增强类型推导。

5. 响应式系统升级
  • Vue2 基于 Object.defineProperty,不能监听新增/删除属性,数组变动支持有限。

  • Vue3 改为基于 Proxy,可以完整监听对象、数组、Map、Set 等数据结构。

6. 生命周期钩子改名(在 Composition API 中)
  • beforeCreatesetup

  • createdsetup

  • 其他钩子加 on 前缀(如 mountedonMounted)。

7. 更灵活的构建方式
  • 支持 自定义渲染器(Custom Renderer) ,不仅能跑在浏览器,还能扩展到小程序、桌面应用等。

  • Vue2 只能依赖 Vue 内核,Vue3 把核心和运行时拆分,更模块化。

2. 简述解释 Vue3 compositon API是什么

1. 什么是 compositon API
  • Composition API 是 Vue3 新增的一套 基于函数的 API,用来组织和复用组件逻辑。

  • 它的核心入口是 setup() 函数,所有逻辑都可以在 setup 里通过函数调用来组合。

  • Composition API = 用函数(setup、ref、reactive、watch 等)来组织逻辑,让代码更清晰、可复用、可维护,特别适合大型项目。

2. 关键点
  • 逻辑集中
    在 Vue2(Options API)里,数据写在 data,方法写在 methods,监听写在 watch,生命周期写在各自钩子里,相关逻辑被拆散。
    Vue3 的 Composition API 允许把同一逻辑写在一起,更清晰。

  • API 函数化
    Vue3 提供 refreactivecomputedwatch 等函数,可以灵活组合来实现响应式。

  • 逻辑复用更强
    可以把一组逻辑封装成 可复用的函数(composition function) ,在不同组件里复用,替代 Vue2 的 mixins。

3. 简述 setup() 函数在 Vue3 中起什么作用

在 Vue3 中,setup() 是组件的核心入口函数,它的作用可以简述为:

1. 初始化组件逻辑
  • 在这里定义响应式数据(refreactive)、计算属性(computed)、监听器(watch)。
2. 替代 Vue2 的 datamethodscomputed
  • 逻辑更集中,不再分散在多个选项里。
3. 返回给模板使用
  • setup() 返回的对象,会暴露给模板(template)使用。
4. 接收组件上下文
  • 通过参数 props 获取父组件传入的数据。
  • 通过 context 获取 attrsslotsemit 等。
5. 逻辑复用
  • 可以调用自定义的组合函数(composition functions),实现逻辑模块化和复用。

4. 简述 ref 和 reactive 的区别

refreactive 的区别

特性refreactive
定义数据用来定义 基本类型(数字、字符串、布尔值等),也可包裹对象用来定义 对象/数组 的响应式
访问方式通过 .value 访问或修改值(模板里自动解包,不需要 .value直接通过属性访问,不需要 .value
返回值返回一个包含 .value 的对象返回对象的 代理 (Proxy)
深层响应式对象类型时,内部属性也是响应式的(ref 内部也用 reactive 实现)默认是 深层响应式(对象嵌套也会被递归代理)
适用场景单一值、原始类型变量复杂对象、数组、集合等
示例:
ref
import { ref } from 'vue'

const count = ref(0)
count.value++   // 修改
console.log(count.value) // 访问
reactive
import { reactive } from 'vue'

const state = reactive({
  count: 0,
  user: { name: 'Alice' }
})
state.count++         // 修改
state.user.name = 'Bob' // 嵌套属性也响应式
总结
  • ref:适合 基本类型 或需要一个独立可变值的情况,要通过 .value 访问。
  • reactive:适合 对象或数组,直接操作属性即可,内部会自动深度代理。

5. 简述 Vue3 中的 watch 和 watchEffect 有何不同

特性watchwatchEffect
监听目标需要显式指定监听的源(如 refreactive 属性、getter 函数)不需要指定,自动收集副作用函数中用到的响应式依赖
是否立即执行默认 不会 立即执行,只有依赖变化时才触发(可设置 immediate: true 让它立即执行)创建时会 立即执行一次,然后依赖变化时再次执行
回调参数回调函数接收 新值和旧值 ((newVal, oldVal) => {})回调函数里 没有新旧值参数,而是直接重新执行整个函数
适用场景更适合 精确侦听某个数据源 的变化更适合 快速响应所有依赖变化(类似自动运行的副作用)
示例:
watch
import { ref, watch } from 'vue'

const count = ref(0)

watch(count, (newVal, oldVal) => {
  console.log(`count: ${oldVal} -> ${newVal}`)
})

count.value++
// 输出:count: 0 -> 1
watchEffect
import { ref, watchEffect } from 'vue'

const count = ref(0)

watchEffect(() => {
  console.log(`count is: ${count.value}`)
})

count.value++
// 输出:
// count is: 0   (立即执行一次)
// count is: 1   (依赖变化再次执行)
总结
  • watch:适合精确监听某个数据源的变化,并能获取新旧值。
  • watchEffect:适合自动收集依赖并立即执行一次,简化逻辑,适合快速响应式副作用。

6. 简述 Vue3 中的 Suspense 组件是如何工作的

1. 什么是 Suspense
  • Suspense 是 Vue3 新增的一个 内置组件
  • 用来 等待异步组件或异步逻辑加载完成,在加载期间展示一个备用 UI(fallback)。
2. 工作原理
  • 异步依赖
    Suspense 包裹的子组件里有 异步组件setup() 里返回 Promise 时,会被认为是「挂起状态」。
  • fallback 占位
    在挂起状态下,Suspense 会先渲染 fallback 插槽里的内容(比如“加载中”)。
  • 完成加载
    等待所有异步依赖完成后,再切换显示 default 插槽里的真实内容。
示例:
<template>
  <Suspense>
    <!-- 默认内容:需要等待 -->
    <template #default>
      <AsyncComponent />
    </template>

    <!-- 占位内容:异步未完成时展示 -->
    <template #fallback>
      <div>加载中...</div>
    </template>
  </Suspense>
</template>

<script setup>
const AsyncComponent = defineAsyncComponent(() =>
  new Promise((resolve) => {
    setTimeout(() => {
      resolve(import('./MyComponent.vue'))
    }, 2000) // 模拟网络延迟
  })
)
</script>

页面效果:
-   前 2 秒显示 `加载中...`。
-   2 秒后显示 `MyComponent` 的内容。
总结

Vue3 的 Suspense 组件通过 等待异步组件或 setup() 中的 Promise,在加载期间展示 fallback 插槽,加载完成后再渲染 default 插槽,从而优雅地处理异步渲染。

7. 简述 Vue3 中的 Teleport 组件有什么作用

1. 什么是 Teleport
  • Teleport 是 Vue3 新增的一个 内置组件
  • 作用是:把子组件的 DOM 结构渲染到指定的 DOM 节点中,而不是渲染在它本来的父组件里。
2. 作用和场景

(1) 脱离父组件层级

  • 解决一些全局 UI(弹窗、模态框、通知、菜单)需要渲染到 body 或应用根节点的问题。

(2) 不影响逻辑归属

  • 虽然 DOM 渲染位置被移动,但逻辑上依然属于原来的组件层级,仍然能访问响应式数据、触发事件。
示例
<template>
  <button @click="show = true">打开弹窗</button>

  <Teleport to="body">
    <div v-if="show" class="modal">
      <p>这里是弹窗内容</p>
      <button @click="show = false">关闭</button>
    </div>
  </Teleport>
</template>

<script setup>
import { ref } from 'vue'
const show = ref(false)
</script>

效果:
-   虽然 `Teleport` 写在当前组件里,但最终渲染的 `<div class="modal">` 会被直接挂到 `<body>` 下。
-   弹窗不会被父容器的 CSS 约束,避免层级问题。
总结

Vue3 的 Teleport 用来 把组件渲染内容传送到指定的 DOM 节点,常用于全局 UI(如模态框、弹窗、提示框),既保持逻辑归属,又能灵活控制渲染位置。

8. 简述 Vue3 如何优化性能

1. 更快的虚拟 DOM
  • Vue3 重写了虚拟 DOM,Diff 算法更高效。
  • 避免不必要的比较,提升更新性能。
2. 编译时优化
  • 静态提升:静态节点只生成一次,后续复用,不再重复创建。
  • 事件缓存:不会在每次渲染时重新生成相同的事件函数。
  • Patch Flag:编译器会给动态节点打标记,运行时只更新有变化的部分。
3. 响应式系统升级
  • Vue2 用 Object.defineProperty,Vue3 改为 Proxy,可以更高效地追踪变化。
  • 支持完整的数据结构(对象、数组、Map、Set 等),避免 Vue2 里的一些性能 hack。
4. 按需 Tree-shaking
  • Vue3 源码模块化设计,未使用的功能不会被打包,体积更小,运行时更快。
5. Fragment 支持
  • 支持多根节点,减少不必要的 DOM 包裹层(Vue2 需要额外的 <div>)。
6. 更高效的组件初始化
  • setup() 逻辑集中,减少组件初始化的开销。
7. Suspense + Teleport 优化渲染体验
  • Suspense:异步组件加载时,先显示占位 UI,避免白屏。
  • Teleport:把弹窗等 DOM 直接渲染到目标位置,避免深层嵌套影响性能。
总结

Vue3 通过 编译优化(静态提升、Patch Flag)+ Proxy 响应式系统 + Tree-shaking + 更快的虚拟 DOM 等手段,大幅提升了性能和渲染效率,同时带来了更好的开发体验。

9. 简述 Vue3 的 provide 和 inject 是如何工作的

1. 什么是 provide / inject
  • provideinject 是 Vue3 提供的 依赖注入机制
  • 用于 跨层级组件通信,避免一层层通过 props 传递数据。
2. 工作方式

(1) 父组件中 provide

  • 使用 provide 定义要共享的数据(键值对)。

(2) 后代组件中 inject

  • 使用 inject 获取到 provide 提供的数据。

⚡ 即使组件层级很深,中间的组件也不需要关心传递,后代可以直接拿到数据。

示例
#父组件
<script setup>
import { provide, ref } from 'vue'

const themeColor = ref('blue')
provide('color', themeColor)
</script>

<template>
  <Child />
</template>
#子孙组件
<script setup>
import { inject } from 'vue'

const color = inject('color', 'defaultColor') // 第二个参数是默认值
</script>

<template>
  <p>主题颜色:{{ color }}</p>
</template>
 这样,`Child` 或更深层组件都能直接拿到 `color`
⚠ 注意点
  1. provide 提供的是 引用(如果是 ref/reactive,会保持响应式)。
  2. inject 拿到的数据就是同一个引用,修改时需要谨慎。
  3. inject 可以设置默认值(当没有对应的 provide 时使用)。
总结

provideinject 就像 “数据发布者”与“订阅者” ,用来在祖先组件和后代组件之间共享数据,避免繁琐的 props 逐层传递,常用于全局配置、主题、依赖注入场景。

10. 简述 Vue3 如何处理组件的异步加载

1. Vue3 异步组件加载的方式

(1) defineAsyncComponent

  • Vue3 提供了一个专门的 API:defineAsyncComponent
  • 用来将一个工厂函数(返回 import() 动态导入的 Promise)包装成异步组件。
import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() =>
  import('./MyComponent.vue')
)

(2) 支持加载状态与错误处理
defineAsyncComponent 可以接收配置对象,添加 loading 组件错误组件延迟/超时控制

const AsyncComp = defineAsyncComponent({
  loader: () => import('./MyComponent.vue'),
  loadingComponent: LoadingComp,   // 加载时显示
  errorComponent: ErrorComp,       // 加载失败时显示
  delay: 200,                      // 延迟显示 loading(毫秒)
  timeout: 3000                    // 超过 3s 报错
})

(3) 结合 <Suspense> 使用
Vue3 新增了 <Suspense> 组件,能优雅处理异步组件加载:

<Suspense>
  <template #default>
    <AsyncComp />
  </template>

  <template #fallback>
    <p>加载中...</p>
  </template>
</Suspense>

👉 fallback 会在 AsyncComp 加载期间显示,加载完成后替换为真正内容。

总结

Vue3 通过 defineAsyncComponent + <Suspense> 提供了强大的异步加载机制,不仅能实现按需加载,还能优雅地处理 加载中状态、错误回退、超时控制,从而优化用户体验和性能。

11. 简述 Vue3 中的响应式系统是如何工作的

1. 基于 Proxy 实现
  • Vue2 使用 Object.defineProperty,只能劫持对象的已有属性。
  • Vue3 使用 ES6 Proxy,可以直接拦截对象的各种操作(读写、删除、遍历等)。
  • 更强大,支持对象、数组、MapSet 等复杂数据结构。
2. 依赖收集 (track)
  • 当组件渲染时,读取响应式数据 → Vue 会通过 Proxy 的 get 捕获操作 → 把当前副作用函数(渲染函数或 watchEffect 等)记录为依赖。
3. 触发更新 (trigger)
  • 当响应式数据发生变化时 → Proxy 的 set 捕获操作 → Vue 通知所有依赖这个数据的副作用函数重新执行 → 从而更新视图。
4. 核心 API
  • reactive():把对象变成响应式代理。
  • ref():用于包装基本类型或对象,生成带 .value 的响应式引用。
  • computed():基于依赖自动缓存的计算属性。
  • effect() / watchEffect():副作用函数,依赖会被自动追踪。
示例
import { reactive, effect } from 'vue'

const state = reactive({ count: 0 })

effect(() => {
  console.log(`count is: ${state.count}`)
})

state.count++
// 输出:count is: 1
// 这里 `effect` 在第一次运行时收集了 `state.count` 依赖,后续修改 `state.count` 时会自动触发更新。
总结

Vue3 的响应式系统基于 Proxy + 依赖收集 + 派发更新 实现,能更高效、全面地追踪数据变化,支持更多数据结构,并为 Composition API 提供了坚实的基础。

12. 简述 Vue3 中的自定义指令是如何定义和使用

1. 在组件中局部注册
<script setup>
const vFocus = {
  mounted(el) {
    el.focus()
  }
}
</script>

<template>
  <input v-focus />
</template>
2. 在应用中全局注册
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// 注册一个全局自定义指令 v-focus
app.directive('focus', {
  mounted(el) {
    el.focus()
  }
})

app.mount('#app')

使用

<input v-focus />
Vue3 自定义指令的生命周期钩子

和 Vue2 类似,但在 Vue3 里名字改动了一点:

  • created:指令绑定到元素时调用(新)。
  • beforeMount:元素插入 DOM 前调用。
  • mounted:元素插入 DOM 后调用。
  • beforeUpdate:所在组件更新前调用。
  • updated:所在组件更新后调用。
  • beforeUnmount:组件卸载前调用。
  • unmounted:组件卸载后调用。
示例
app.directive('color', {
  beforeMount(el, binding) {
    el.style.color = binding.value
  },
  updated(el, binding) {
    el.style.color = binding.value
  }
})

用法

<p v-color="'red'">这段文字是红色</p>
总结

Vue3 的自定义指令通过 app.directive(全局)或对象语法(局部)定义,提供了一系列生命周期钩子,可以在元素挂载、更新、卸载时操作 DOM,常用于 聚焦、样式控制、权限控制等 DOM 操作场景

13. 简述 Vue3 (Vue Router 4)中的路由和 Vue2 (Vue Router 3)有哪些变化

1. 安装和创建方式变化
# vue2
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)

const router = new VueRouter({ routes })
new Vue({ router }).$mount('#app')
# vue3
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes
})

const app = createApp(App)
app.use(router)
app.mount('#app')
2. history 创建方式不同

Vue2:mode: 'history' | 'hash'

Vue3:通过 工厂函数 创建

  • createWebHistory() → history 模式
  • createWebHashHistory() → hash 模式
  • createMemoryHistory() → SSR 场景
3. Composition API 支持更好

提供了基于 Vue3 的 setup() 使用的组合式 API:

  • useRouter() → 获取路由实例
  • useRoute() → 获取当前路由对象
import { useRouter, useRoute } from 'vue-router'

const router = useRouter()
const route = useRoute()

router.push('/home')
console.log(route.params.id)

4. 动态路由和类型支持更强
  • Vue Router4 更好地支持 TypeScript,路由参数有类型推导。

  • 动态路由添加/删除方式简化:

router.addRoute({ path: '/about', component: About })
router.removeRoute('about')
5. 路由守卫改进
  • 使用方式基本相同,但 Vue Router4 内部基于 Promise 机制,支持 async/await,可以更优雅地写异步逻辑。
6. 更好的错误处理
  • 重复导航报错(如多次 push 同一路由),Vue Router4 会自动忽略,不需要手动 catch
总结

Vue3 使用的 Vue Router 4 在 API 设计上更符合 Vue3 风格:

  • 使用 createRouter + 工厂函数创建 history
  • 提供组合式 API (useRouter / useRoute)
  • 改进动态路由和 TypeScript 支持
  • 更好的错误和异步处理

14. Vue3 如何与 Vuex4 一起使用

1. Vuex4 是什么
  • Vuex4 是为 Vue3 适配的状态管理库。

  • API 和 Vuex3(Vue2 用的版本)基本一致,只是底层适配了 Vue3 的 createApp

  • 如果你熟悉 Vuex3,上手 Vuex4 几乎没有学习成本。

2. 使用步骤
(1)安装 Vuex4
npm install vuex@4
(2)创建 Store

store/index.js 中:

import { createStore } from 'vuex'

const store = createStore({
  state() {
    return {
      count: 0
    }
  },
  mutations: {
    increment(state) {
      state.count++
    }
  },
  actions: {
    asyncIncrement({ commit }) {
      setTimeout(() => {
        commit('increment')
      }, 1000)
    }
  },
  getters: {
    doubleCount(state) {
      return state.count * 2
    }
  }
})

export default store
(3)在 Vue 应用中挂载 Store

main.js 中:

import { createApp } from 'vue'
import App from './App.vue'
import store from './store'

const app = createApp(App)
app.use(store)
app.mount('#app')
(4)在组件中使用

方式一:选项式 API

<template>
  <div>
    <p>count: {{ $store.state.count }}</p>
    <button @click="$store.commit('increment')">+1</button>
  </div>
</template>

方式二:组合式 API(推荐)

Vuex4 提供了 useStore(),适配 Vue3 的 setup()

<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'

const store = useStore()

const count = computed(() => store.state.count)
const doubleCount = computed(() => store.getters.doubleCount)

const increment = () => {
  store.commit('increment')
}
</script>

<template>
  <div>
    <p>count: {{ count }}</p>
    <p>double: {{ doubleCount }}</p>
    <button @click="increment">+1</button>
  </div>
</template>
总结

在 Vue3 中使用 Vuex4:

  • createStore 创建 Store
  • main.js 里通过 app.use(store) 挂载
  • 在组件中既能用 $store,也能在 setup() 里用 useStore(),更贴合组合式 API。

15. 简述 Vue3 的插槽和 Vue2 有何不同

16. 简述 Vue3 中的过渡和动画效果是如何实现的

17. 简述 Vue3 的服务器渲染(SSR)是如何工作的

18. 简述 Vue3 中的虚拟DOM是如何工作的

19. 简述 Vue3 如何处理全局状态

20. 简述 Vue3 的生命周期钩子有哪些变化

21. 简述 Vue3 如何与 TypeScript 一起使用

22. 简述 Vue3 的事件修饰符有哪些

23. 简述 Vue3 中的 Fragment 是什么

24. 简述 Vue3 如何实现组件的懒加载

25. 简述 Vue3 如何与 Web Components 集成

26. 简述 Vue3 如何支持碎片(Fragment)

27. Vue3 和 Vue2 的响应式原理的区别

28. 简述 Object.DefineProperty 和 Proxy 的区别

29. 简述 setup 方法和 setup 语法糖的区别

30. 简述 Vue3 双向数据绑定的原理是什么,与 Vue2 有什么不同

31. 简述 Vue3 中使用了哪些 ES6 的技术或 API

32. 简述什么是 Vue3 的 Proxy API,它如何用于数据代理

33. 简述在 Vue3 中,如何使用 Composition API 更好地组织和管理代码

34. 简述 Vue3 中,如何使用 Teleport 将组件的子组件渲染到DOM树的任意位置