Code前端首页关于Code前端联系我们

Vue3 高频面试题,这些知识点面试前一定要搞懂

terry 1天前 阅读数 22 #SEO
文章标签 Vue3面试题

组合式 API 和选项式 API 有啥区别?该怎么选?

很多同学刚接触 Vue3 时,会纠结用组合式 API(Composition API)还是选项式 API(Options API),简单说,选项式是“按功能拆分”,把数据、方法、生命周期分散在 datamethodscomputed 这些选项里;组合式是“按逻辑聚合”,通过 setup 函数把相关逻辑(比如获取用户信息、处理表单提交)集中在一块,用 refreactive 这些 API 组织代码。

选的时候看场景:如果是新手写小项目,选项式更直观,不用记新 API;但中大型项目、逻辑复杂的页面(比如表单校验 + 异步请求 + 权限控制),组合式优势就来了——它能通过「自定义 Hook」复用逻辑(比如把请求用户信息的逻辑封装成 useUser,多个组件直接 import),还能避免选项式里 mixins 命名冲突、逻辑来源模糊的问题,组合式对 TypeScript 更友好,类型推导一步到位,写 TS 项目优先选它。

Vue3 响应式原理和 Vue2 有啥不一样?Proxy 好在哪?

Vue2 靠 Object.defineProperty 实现响应式:遍历对象每个属性,给属性加 getter/setter 劫持读写,但有不少痛点——比如新增属性、删除属性监听不到(Vue2 要写 $set$delete),数组下标修改也监听不到(得用 splice 这类重写的方法)。

Vue3 换成了 Proxy直接代理整个对象,能监听更多操作:新增属性、删除属性、数组长度变化都能感知到,不用再手动调 $setProxy 是“懒代理”,访问对象属性时才去处理,不像 Object.defineProperty 要递归遍历所有属性(大对象性能差),举个例子,一个有 100 个属性的对象,Vue2 初始化时要遍历 100 次加劫持,Vue3 只在访问某个属性时才处理,性能和灵活性都提升了。

setup 函数是干啥的?执行时机和参数咋理解?

setup 是组合式 API 的入口,在组件创建前执行(比 beforeCreate 还早),负责准备组件的响应式数据、方法这些,它接收两个参数:

  • props:父组件传的属性,是“响应式”的!但注意不能直接解构,否则会失去响应性(const { msg } = props 后,msg 就不是响应式了,得用 toRefs(props) 解构)。
  • context:包含 attrs(父组件非 props 属性)、slots(插槽)、emit(触发自定义事件)、expose(暴露方法给父组件)这些,是“非响应式”的,解构了也没事。

setup 返回的对象或函数,会变成模板里能直接用的变量/方法,比如返回 { count, increment },模板里就能写 {{ count }}@click="increment"

ref 和 reactive 区别是啥?咋选场景?

一句话总结:ref 更灵活,reactive 更“整”

  • ref 既能包基本类型(字符串、数字、布尔),也能包对象数组,它内部靠 value 属性实现响应式(const count = ref(0),改的时候要 count.value++)。
  • reactive 只能代理对象/数组,而且不能直接解构(解构后变成普通对象,失去响应性),它适合给“整个对象”做响应式,比如用户信息对象 const user = reactive({ name: '张三', age: 18 })

场景建议:基本类型优先用 ref;对象/数组如果需要“整体替换”(user = { name: '李四' }),用 ref 包对象更方便;如果只是修改对象内部属性(user.age++),用 reactive 更简洁。

computed 和 watch 在 Vue3 咋用?和 Vue2 有啥区别?

先看 computed:Vue3 里是个函数,导入后用 const 全名 = computed(() => 依赖值计算),还支持“可写计算属性”(传对象,配 getset),比如做购物车总价:

const total = computed(() => goodsList.reduce((sum, item) => sum + item.price, 0))

再看 watch:Vue3 有 watchwatchEffect 两个 API。watch 要“指定监听源”(refreactive 的属性、getter 函数),支持配置 immediate(立即执行)、deep(深度监听)。watchEffect 更“懒”,自动收集依赖,执行时用到啥就监听啥,适合处理副作用(比如请求数据)。

和 Vue2 区别:Vue2 的 computedwatch 是写在选项里的,Vue3 能在 setup 或自定义 Hook 里用,更灵活。watchEffect 是 Vue3 新增的,写异步逻辑、自动依赖收集特别香。

Composition API 比 mixins 好在哪?

mixins 是 Vue2 里复用逻辑的方案,但坑很多:命名冲突(多个 mixins 有同名方法,后引入的会覆盖)、依赖模糊(组件里用了某个方法,分不清是自己写的还是 mixins 来的)、逻辑分散(数据和方法散在各个 mixins,维护时要跳来跳去)。

Composition API 用「自定义 Hook」解决这些问题:比如把“获取用户信息 + 处理用户状态”的逻辑封装成 useUser(),组件里 import { useUser } from './hooks' 后,直接用返回的 userInfoupdateUser,逻辑来源清晰,还能传参控制(useUser(123) 指定用户 ID),而且和 TS 结合更丝滑,类型能自动推导,不用像 mixins 那样手动声明类型。

Teleport 组件是干啥的?项目里咋用?

Teleport 直译是“传送门”,作用是把组件里的内容“传送”到页面任意 DOM 节点body 标签里),最典型的场景是模态框、下拉菜单——如果它们被嵌套在有 overflow: hiddenz-index 层级低的父组件里,样式会乱掉,用 Teleport 把弹窗内容直接挂到 body 下,就能避免这些问题。

用法很简单:

<template>
  <button @click="showModal = true">打开弹窗</button>
  <Teleport to="body">
    <div v-if="showModal" class="modal">
      我是弹窗内容,现在渲染到 body 里啦!
    </div>
  </Teleport>
</template>

注意 to 可以是 CSS 选择器(#app.container)或 DOM 元素,Teleport 内部的组件和父组件上下文是通的,能正常用 propsemit 这些。

Suspense 组件咋理解?适合啥场景?

Suspense 是 Vue3 里处理异步组件加载的“占位组件”,能优雅展示“加载中”“加载错误”状态,比如路由懒加载时,组件还没下载完,就显示个 Loading 动画;或者组件依赖异步数据(比如请求接口后渲染),也能用 Suspense 控制加载状态。

用法示例:

<template>
  <Suspense>
    <template #default>
      <AsyncComponent /> <!-- 异步组件,比如用 defineAsyncComponent 定义 -->
    </template>
    <template #fallback>
      <div>加载中...</div>
    </template>
  </Suspense>
</template>

场景建议:路由组件懒加载、依赖异步数据的组件(比如图表组件要等接口返回数据才渲染),不过要注意,Suspense 现在需要结合错误边界(onErrorCaptured 钩子)处理加载失败的情况,避免页面崩掉。

Vue3 自定义指令咋实现?和 Vue2 有啥区别?

Vue3 自定义指令的钩子函数更贴近组件生命周期

  • created:指令绑定到元素前调用(还没创建 DOM)
  • beforeMount:元素挂载到 DOM 前
  • mounted:元素挂载后(常用,比如做自动聚焦)
  • beforeUpdate:组件更新前
  • updated:组件更新后
  • beforeUnmount:元素卸载前
  • unmounted:元素卸载后

注册方式分全局和局部:

// 全局指令:main.js
app.directive('focus', {
  mounted(el) {
    el.focus() // 挂载后自动聚焦
  }
})
// 局部指令:组件内
directives: {
  focus: {
    mounted(el) {
      el.focus()
    }
  }
}

和 Vue2 区别:Vue2 的钩子是 bind(绑定)、inserted(插入 DOM)、update 这些,Vue3 改名后更直观,和组件生命周期的命名逻辑统一了。

Vue3 性能优化做了哪些改进?开发咋用这些特性?

Vue3 从编译、响应式、打包三方面做了优化:

  1. 编译优化

    • 静态提升:把不变的节点(比如纯文本、无指令的元素)编译后复用,减少创建开销。<div>固定文案</div> 会被标记为静态节点,只创建一次。
    • 补丁标记:给动态节点加更细的标记(v-ifv-for 节点区分开),Diff 时能快速跳过静态节点,减少比对时间。
    • 事件缓存:内联事件处理函数(@click="() => doSomething")会被自动缓存,避免每次渲染都创建新函数。
  2. 响应式优化:用 Proxy 懒代理对象,访问属性时才处理响应式,不用像 Vue2 那样递归遍历所有属性,大对象性能更好。

  3. Tree-shaking:Vue3 的 API 是 ES 模块导出,打包时只包含用到的部分(比如只用了 ref 就不会打包 reactive),体积更小。

开发时咋用?比如写模板时,把静态内容尽量提取到组件外;事件处理函数用内联写法(Vue3 会自动缓存);配合 Vite 打包,利用其基于 ESM 的快速启动和热更新。

Pinia 和 Vuex 咋选?核心区别是啥?

Pinia 是 Vue 官方现在主推的状态管理库,比 Vuex 更轻量、简洁,核心区别:

  • 语法层面:Vuex 需要定义 mutations(必须同步)、actions(异步)、getters,结构繁琐;Pinia 没有 mutations,只有 stategettersactions(actions 能同步也能异步),用 defineStore 定义 Store,写法更自由。
  • TS 支持:Pinia 对 TypeScript 更友好,状态、方法的类型能自动推导,不用像 Vuex 那样手动写很多类型声明。
  • 体积和性能:Pinia 体积更小(不到 Vuex 的 1/3),性能更好,没有 Vuex 里复杂的模块嵌套逻辑。

新项目直接选 Pinia 就行,简单高效;老项目如果用 Vuex 且不想迁移,继续用也没问题。

Vite 和 Vue CLI 构建 Vue3 项目有啥不同?为啥推荐 Vite?

核心差异在构建原理

  • Vue CLI 基于 Webpack,开发时要把所有代码打包后再启动,项目大了启动慢、热更新也慢;
  • Vite 基于 ES 模块(ESM),开发时不打包,直接按需加载浏览器支持的 ESM 文件,启动秒开,热更新也是毫秒级。

Vite 打包用 Rollup,比 Webpack 更高效,体积更小;配置也更简洁,不用写一堆 loaderplugin,Vue3 官方模板默认用 Vite,就是因为开发体验好太多,Webpack 生态更成熟,如果项目需要复杂的自定义打包逻辑(比如老项目迁移、特殊 loader),暂时用 Vue CLI 也能过渡,但长远看 Vite 是趋势。

Vue2 项目迁 Vue3 要注意啥?

迁移分“语法兼容”和“代码重构”两步:

  1. Breaking Change 处理

    • 过滤器(filter)移除:改用方法或计算属性。{{ msg | uppercase }} 改成 {{ toUppercase(msg) }}
    • 实例方法移除:$on$off$once 没了,事件总线得换第三方库(mitt)。
    • 生命周期改名:beforeDestroybeforeUnmountdestroyedunmounted
    • v-model 语法:Vue3 里 v-model 等价于 modelValue + @update:modelValue,还支持多个 v-model<Child v-model:name="name" v-model:age="age" />)。
  2. 代码重构

    • 逐步替换组件:先用 Vue 官方的「迁移构建工具」(@vue/compat),让 Vue3 兼容 Vue2 API,再慢慢把组件改成组合式 API。
    • 第三方库兼容:检查 UI 库、请求库等是否支持 Vue3,不支持的话得找替代方案。

如果项目不大,直接用组合式 API 重写更彻底;项目大就用迁移工具分步来,风险更低。

Vue3 结合 TypeScript 有啥实践技巧?

Vue3 对 TS 支持比 Vue2 好太多,这些技巧能少踩坑:

  • 组件定义:用 defineComponent 包裹组件,让 TS 推导组件选项类型。

    import { defineComponent } from 'vue'
    export default defineComponent({
      props: { msg: String },
      setup() { /* ... */ }
    })
  • 响应式数据类型ref 用泛型(ref<number>(0)),reactive 用接口(interface User { name: string }; const user = reactive<User>({ name: '' }))。

  • Props 类型:用 TS 语法声明 defineProps<{ msg: string; count?: number }>(),还能结合 withDefaults 设默认值:

    withDefaults(defineProps<{ msg: string; count?: number }>(), { count: 0 })
  • Emits 类型:用 defineEmits<{ (e: 'change', value: number): void }>() 明确事件和参数类型,避免传错参数。

  • 自定义 Hook:给 Hook 的参数、返回值写清楚类型,function useFetch<T>(url: string): Ref<T | null> { ... },复用时代码提示更友好。

Vue3 的 SSR 和 Vue2 比有啥改进?开发要注意啥?

Vue3 对 SSR(服务端渲染)的支持更高效,主要体现在:

  • 异步处理更丝滑:结合 Composition API 和 Suspense,能优雅处理异步组件、异步数据加载(比如组件里用 await 请求数据,Suspense 自动处理加载状态)。
  • 性能提升:基于 Vite 的 SSR 方案启动更快,打包更优,内存占用更低。

开发时要注意这些点:

  • 避免浏览器 API:服务端渲染时没有 windowdocument,DOM 操作要放到 onMounted 等客户端钩子中。
  • 样式处理:如果用 CSS-in-JS 或 scoped CSS,要确保服务端能正确注入样式,避免客户端 Hydration 时样式错乱。
  • 状态序列化:服务端渲染的状态要传递到客户端(比如用 window.__INITIAL_STATE__),否则客户端重新请求数据会导致界面闪烁(Hydration Mismatch)。

Nuxt3 基于 Vue3 和 Vite,把 SSR 配置简化了,想做服务端渲染的项目可以优先考虑。

Vue3 面试绕不开「响应式原理变化」「组合式 API 深度」「新组件(Teleport/Suspense)」「性能优化」「生态工具(Pinia/Vite)」这些核心点,把这些问题吃透,不仅面试更有底气,实际开发时也能更高效地驾驭框架~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门