Skip to content

Vue 热点面试题

1. Vue 3 Composition API vs Options API 的区别与选择

问题:

Vue 3 引入的 Composition API 与传统的 Options API 有什么主要区别?在实际项目中应该如何选择?

答案:

Composition API 与 Options API 的主要区别:

  1. 代码组织方式

    • Options API:通过 datamethodscomputed 等选项组织代码,逻辑分散
    • Composition API:使用函数形式组织相关逻辑,逻辑可以聚合
  2. 逻辑复用

    • Options API:通过混入 (mixins) 复用逻辑,但容易导致命名冲突和来源不清
    • Composition API:通过组合函数 (Composables) 复用逻辑,更清晰且避免冲突
  3. TypeScript 支持

    • Options API:类型推导有限,需要额外的类型声明
    • Composition API:更好的 TypeScript 支持,自动类型推导更完善
  4. 代码压缩效率

    • Options API:对象键名无法被压缩
    • Composition API:局部变量名可以被压缩,更小的打包体积

选择建议:

  • 小型组件或简单逻辑:Options API 更直观
  • 大型组件或复杂逻辑:Composition API 更好维护
  • 需要逻辑复用:优先使用 Composition API 的组合函数
  • TypeScript 项目:推荐使用 Composition API
javascript
// Options API 示例
export default {
  data() {
    return { count: 0 }
  },
  methods: {
    increment() { this.count++ }
  }
}

// Composition API 示例
import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const increment = () => { count.value++ }
    return { count, increment }
  }
}

2. Vue 3 的响应式系统原理

问题:

Vue 3 的响应式系统相比 Vue 2 有什么改进?请解释其实现原理。

答案:

Vue 3 响应式系统的改进:

  1. 性能提升

    • Vue 2:使用 Object.defineProperty,递归遍历所有属性
    • Vue 3:使用 Proxy,懒代理,只在需要时才代理嵌套对象
  2. 功能增强

    • Vue 2:无法监听属性添加/删除、数组索引/长度变化
    • Vue 3:原生支持监听属性添加/删除、数组操作等
  3. 类型友好

    • 更好的 TypeScript 集成

实现原理: Vue 3 使用 ProxyReflect 实现响应式系统,主要包含以下核心函数:

  • reactive:创建响应式对象
  • ref:创建响应式基本类型包装器
  • computed:创建计算属性
  • watch/watchEffect:监听响应式数据变化
javascript
// 简化的响应式系统核心逻辑
function reactive(target) {
  return new Proxy(target, {
    get(target, key, receiver) {
      const result = Reflect.get(target, key, receiver)
      track(target, key)
      // 懒递归代理
      if (isObject(result)) {
        return reactive(result)
      }
      return result
    },
    set(target, key, value, receiver) {
      const oldValue = target[key]
      const result = Reflect.set(target, key, value, receiver)
      if (oldValue !== value) {
        trigger(target, key)
      }
      return result
    }
  })
}

3. Vue 3 中的 Teleport 组件

问题:

Vue 3 中的 Teleport 组件有什么作用?请提供使用场景和示例。

答案:

Teleport 的作用: Teleport 提供了一种简洁的方式,允许我们将组件的模板渲染到 DOM 树中的任何位置,而不受组件层次结构的限制。

使用场景:

  1. 模态对话框 (Modal)
  2. 通知提示 (Notification)
  3. 浮动菜单 (Dropdown)
  4. 加载指示器 (Loader)

使用示例:

html
<!-- Modal.vue 组件 -->
<template>
  <Teleport to="body">
    <div v-if="isOpen" class="modal-overlay">
      <div class="modal-content">
        <slot></slot>
        <button @click="close">关闭</button>
      </div>
    </div>
  </Teleport>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue'

const props = defineProps(['isOpen'])
const emit = defineEmits(['close'])

const close = () => {
  emit('close')
}
</script>

4. Vue 3 中的 Pinia 状态管理

问题:

Pinia 相比 Vuex 有什么优势?请简述其核心概念和使用方式。

答案:

Pinia 相比 Vuex 的优势:

  1. 更简洁的 API

    • 没有 mutations,直接在 actions 中修改状态
    • 不需要使用 mapState、mapGetters 等辅助函数
  2. 更好的 TypeScript 支持

    • 自动类型推导,无需额外的类型声明
  3. 组合式 API 支持

    • 可以在 store 中直接使用 Composition API
  4. 模块化设计

    • 每个 store 都是独立的模块,无需嵌套

核心概念:

  • State:存储状态
  • Getters:计算属性
  • Actions:修改状态的方法(支持同步和异步)

使用示例:

javascript
// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  getters: {
    doubleCount: (state) => state.count * 2
  },
  actions: {
    increment() {
      this.count++
    },
    async incrementAsync() {
      await new Promise(resolve => setTimeout(resolve, 1000))
      this.count++
    }
  }
})

// 组件中使用
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'

export default {
  setup() {
    const counter = useCounterStore()
    // 使用 storeToRefs 保持响应性
    const { count, doubleCount } = storeToRefs(counter)
    
    return {
      count,
      doubleCount,
      increment: counter.increment
    }
  }
}

5. Vue 3 的虚拟 DOM 优化

问题:

Vue 3 对虚拟 DOM 做了哪些优化?这些优化如何提升性能?

答案:

Vue 3 虚拟 DOM 优化:

  1. 静态提升 (Static Hoisting)

    • 编译时标记静态节点
    • 避免重复创建静态节点
    • 静态属性也会被提取
  2. Patch Flag 优化

    • 编译时为动态节点添加标记
    • 运行时只更新有变化的属性
    • 减少不必要的比对
  3. 事件缓存

    • 缓存事件处理函数
    • 避免每次渲染都创建新的函数实例
  4. Block Tree 结构

    • 将模板分割成嵌套的 Block
    • 只比对 Block 内的动态节点

性能提升:

  • 减少虚拟 DOM 的创建成本
  • 减少不必要的节点比对
  • 提高渲染和更新的效率
javascript
// 编译优化示例
// 原始模板
<div>
  <span>静态文本</span>
  <span :id="dynamicId">{{ dynamicText }}</span>
</div>

// Vue 3 编译后的代码会包含优化标记
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock } from 'vue'

const _hoisted_1 = /*#__PURE__*/ _createElementVNode("span", null, "静态文本", -1 /* HOISTED */)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("div", null, [
    _hoisted_1,
    /*#__PURE__*/ _createElementVNode("span", { id: _ctx.dynamicId }, _toDisplayString(_ctx.dynamicText), 8 /* PROPS */, ["id"])
  ]))
}

6. Vue 中的自定义渲染器 (Custom Renderer)

问题:

Vue 3 的自定义渲染器是什么?它有什么应用场景?

答案:

自定义渲染器定义: 自定义渲染器允许开发者创建非 DOM 平台的渲染器,使 Vue 组件可以在不同环境中运行,而不仅限于浏览器。

应用场景:

  1. 跨平台应用

    • 移动端原生应用(如 Weex、React Native 类似的方案)
    • 桌面应用(如使用 Electron)
  2. 游戏开发

    • 使用 Canvas 或 WebGL 渲染 Vue 组件
  3. 特殊显示环境

    • 智能电视界面
    • VR/AR 应用界面

基本实现:

javascript
import { createRenderer } from 'vue'

const { render, createApp } = createRenderer({
  // DOM 创建相关
  createElement(type) {
    // 平台特定的元素创建
    return { type }
  },
  
  // 属性设置
  patchProp(el, key, prevValue, nextValue) {
    // 平台特定的属性更新
    el[key] = nextValue
  },
  
  // 子节点操作
  insert(el, parent, anchor) {
    // 平台特定的节点插入
  },
  
  remove(el) {
    // 平台特定的节点移除
  },
  
  // 文本节点
  createText(text) {
    // 平台特定的文本节点创建
    return { text }
  },
  
  setText(node, text) {
    // 平台特定的文本更新
    node.text = text
  },
  
  createComment(text) {
    // 平台特定的注释创建
    return { text, type: 'comment' }
  }
})

7. Vue 3 中的 Suspense 组件

问题:

Suspense 组件的作用是什么?它如何简化异步组件的处理?

答案:

Suspense 的作用: Suspense 是 Vue 3 提供的一个内置组件,用于处理异步组件加载过程中的等待状态和错误处理。

主要功能:

  1. 统一的加载状态管理

    • 使用 <template #fallback> 定义加载中的 UI
  2. 错误边界

    • 配合错误处理机制,可以捕获异步组件加载错误
  3. 简化异步操作

    • 减少手动管理加载状态的代码

使用示例:

html
<Suspense>
  <template #default>
    <AsyncComponent />
  </template>
  <template #fallback>
    <div>Loading...</div>
  </template>
</Suspense>

<!-- 异步组件定义 -->
const AsyncComponent = defineAsyncComponent({
  loader: () => import('./HeavyComponent.vue'),
  loadingComponent: LoadingComponent,
  delay: 200,
  timeout: 3000,
  errorComponent: ErrorComponent,
  onError(error, retry, fail, attempts) {
    if (error.message.match(/fetch/) && attempts <= 3) {
      retry()
    } else {
      fail()
    }
  }
})

8. Vue 3 中的模板编译优化

问题:

Vue 3 的模板编译做了哪些优化?这些优化如何提升应用性能?

答案:

Vue 3 模板编译优化:

  1. 静态分析

    • 编译时分析模板,标记静态和动态内容
  2. 预编译

    • 将模板预编译为渲染函数,减少运行时编译开销
  3. 按需更新

    • 使用 Patch Flags 标记动态节点,运行时只更新必要的部分
  4. 缓存优化

    • 缓存事件处理器、静态内容等

性能提升:

  • 减少 JavaScript 执行时间
  • 降低内存使用
  • 提高渲染和更新速度
  • 减小打包体积

9. Vue 中的 KeepAlive 组件

问题:

KeepAlive 组件的作用是什么?它的实现原理是什么?有哪些使用场景?

答案:

KeepAlive 的作用: KeepAlive 是 Vue 的一个内置组件,用于缓存不活动的组件实例,避免组件的重复创建和销毁,提高性能。

实现原理:

  1. 组件缓存

    • 使用一个 Map 或对象存储缓存的组件实例
  2. 生命周期钩子

    • 当组件被 KeepAlive 包裹时,会触发 activateddeactivated 生命周期钩子
  3. 条件缓存

    • 支持 includeexclude 属性来控制哪些组件需要被缓存

使用场景:

  1. Tab 切换

    • 缓存不同 Tab 页的状态
  2. 路由切换

    • 缓存页面组件的状态
  3. 复杂表单

    • 保持表单输入状态

使用示例:

html
<KeepAlive include="TabA,TabB" exclude="TabC" max="10">
  <component :is="currentTab"></component>
</KeepAlive>

10. Vue 3 中的性能优化技巧

问题:

在 Vue 3 项目中,有哪些常用的性能优化技巧?

答案:

Vue 3 性能优化技巧:

  1. 使用 v-memo 指令

    • 缓存模板的一部分,避免不必要的更新
  2. 合理使用 v-once

    • 对于静态内容,使用 v-once 只渲染一次
  3. 虚拟滚动

    • 对于长列表,使用虚拟滚动库(如 vue-virtual-scroller)
  4. 异步组件

    • 使用 defineAsyncComponent 实现组件懒加载
  5. 正确使用响应式 API

    • 避免在模板中使用复杂计算
    • 使用 shallowRefshallowReactive 处理大对象
  6. 优化组件拆分

    • 合理拆分组件,提高复用性和渲染性能
  7. 使用 suspense 优化加载体验

    • 统一管理异步组件的加载状态
javascript
// 使用 v-memo 示例
<div v-memo="[valueA, valueB]">
  {{ valueA }} 和 {{ valueB }}
</div>

// 使用 shallowRef 处理大对象
const largeObject = shallowRef({ /* 大型对象 */ })

面试题总结与背诵指南

核心概念速记:

  1. Composition API 核心优势:逻辑聚合、更好复用、TypeScript 友好

  2. Vue 3 响应式系统:Proxy 实现,懒代理,支持新增/删除属性

  3. Pinia vs Vuex:无 mutations,更好的 TS 支持,更简洁的 API

  4. 虚拟 DOM 优化:静态提升、Patch Flag、Block Tree

  5. 高级组件

    • Teleport:跨 DOM 边界渲染
    • Suspense:异步组件加载状态管理
    • KeepAlive:缓存组件实例

回答技巧:

  1. 先概述,后细节:先给出核心概念,再展开细节

  2. 结合实际场景:说明在什么情况下使用什么技术

  3. 对比分析:如 Vue 2 vs Vue 3,Options API vs Composition API

  4. 代码示例:准备简洁的代码示例来支撑你的回答

  5. 性能考量:回答中体现对性能优化的理解

记住这些核心要点,面试时根据具体问题灵活展开,重点突出你对 Vue 3 新特性的理解和实际应用经验。

Updated at:

Released under the MIT License.