8.1 Composition API


文档摘要

Vue 3 Composition API 详解:现代组件逻辑组织与代码复用指南 摘要:本文深入解析 Vue 3 Composition API 的核心概念、优势及实战应用。从 Options API 的局限性出发,详细讲解 函数、响应式 API、生命周期钩子及 Composables 组合式函数,并补充 语法糖的最佳实践,助力开发者构建高可维护性、高扩展性的现代 Vue.js 应用。 8.1 Composition API:Vue 3 的核心逻辑组织方案 在 Vue.js 的发展历程中,组件逻辑的组织方式经历了从 Options API 到 Composition API 的重大转变。Options API 以其简洁易懂的结构,让开发者能够快速上手。

Vue 3 Composition API 详解:现代组件逻辑组织与代码复用指南

摘要:本文深入解析 Vue 3 Composition API 的核心概念、优势及实战应用。从 Options API 的局限性出发,详细讲解 setup() 函数、响应式 API、生命周期钩子及 Composables 组合式函数,并补充 <script setup> 语法糖的最佳实践,助力开发者构建高可维护性、高扩展性的现代 Vue.js 应用。

8.1 Composition API:Vue 3 的核心逻辑组织方案

在 Vue.js 的发展历程中,组件逻辑的组织方式经历了从 Options API 到 Composition API 的重大转变。Options API 以其简洁易懂的结构,让开发者能够快速上手。然而,随着前端工程化和组件复杂度的提升,Options API 在代码复用和逻辑组织方面逐渐显露出局限性。为解决这些痛点,Vue 3 引入了 Composition API。这是一种全新的、基于函数的 API 集合,旨在提供更灵活、更强大的组件逻辑组织和复用机制。

本章节将深入探讨 Composition API 的核心概念、技术优势以及在实际项目中的最佳实践。

8.1.1 Options API 的局限性与 Composition API 的诞生

在深入探讨前,回顾 Options API 并分析其在大型复杂组件中面临的挑战,有助于更好地理解 Composition API 诞生的背景和意义。

Options API 的优势与不足

Options API 通过预定义的选项(如 datamethodscomputedwatch 和生命周期钩子)将组件逻辑划分为不同模块。这种结构化的方式对小型组件非常友好,易于理解和上手。

<template> <div> <p>Count: {{ count }}</p> <button @click="increment">Increment</button> </div> </template> <script> export default { data() { return { count: 0 }; }, methods: { increment() { this.count++; } }, mounted() { console.log('Component mounted'); } }; </script>

然而,当组件变得庞大且复杂时,Options API 的局限性开始显现:

  • 逻辑分散:当组件功能增多时,相关的逻辑会被迫分散在 datamethodscomputedwatch 等不同选项中。同一个业务功能的代码需要在多个配置块之间反复横跳,导致代码难以阅读和维护。
  • 代码复用困难:在 Options API 中,逻辑复用主要依赖 Mixins。但 Mixins 存在命名冲突、数据来源不清晰(隐式依赖)等问题,使得大规模复用变得复杂且易错。
  • 类型推导挑战:Options API 中的 this 上下文在 TypeScript 环境下类型推导困难,需要借助额外的包装函数(如 defineComponent)或类型断言才能获得良好的类型支持。

为克服上述局限,Vue 3 推出了 Composition API。其核心思想是将组件逻辑组织从“配置选项”转向“函数组合”,通过将相关逻辑封装在函数中,并利用响应式 API,实现更灵活、高内聚的代码组织方式。

Composition API 的核心理念

  • 基于函数:使用函数来组织和复用组件逻辑,摆脱对象配置的限制。
  • 组合式:将组件逻辑拆分成小的、独立的函数(Composables),像搭积木一样组合构建复杂组件。
  • 逻辑内聚:将与同一业务功能相关的代码集中在一起,大幅提升代码可读性。
  • 完美的类型推导:天然契合 TypeScript,提供卓越的静态类型检查和推导能力。

8.1.2 Composition API 的核心组成部分

Composition API 由一系列底层 API 组成,最核心的部分包括 setup() 函数、响应式 API 和生命周期钩子。

8.1.2.1 setup() 函数:Composition API 的入口

setup() 函数是 Composition API 的入口点。作为一个新的组件选项,它在组件实例创建之前被调用,是编写组合式逻辑的主要场所。

<script> import { ref } from 'vue'; export default { setup() { const count = ref(0); function increment() { count.value++; } return { count, increment }; } }; </script>

setup() 函数的核心特性:

  • 执行时机:在 beforeCreatecreated 生命周期钩子之前执行。这意味着在 setup() 中无法访问 datamethods 等 Options API 选项,也无法访问 this 实例。
  • 返回值:可返回一个对象,其属性会被合并到组件的渲染上下文中,供模板直接使用;也可返回渲染函数(Render Function)。
  • 参数接收
    • props:响应式的父组件传递的属性对象。
    • context:上下文对象,包含 attrsslotsemitexpose

图示:setup() 函数的执行时机

8.1.2.2 响应式 API:构建动态数据的基石

Composition API 提供了强大的响应式系统,核心 API 包括:

  • ref():用于创建基本数据类型(数字、字符串、布尔值)和对象类型的响应式数据。对于基本类型,会包装成带有 .value 属性的对象;对于对象类型,内部会调用 reactive()
  • reactive():专用于创建对象类型(Object、Array、Map、Set)的深层响应式代理。直接访问和修改属性即可触发更新。
  • computed():创建计算属性。接收 getter 函数,根据依赖的响应式数据自动计算并缓存结果。
  • watch()watchEffect():用于监听数据变化并执行副作用。watch() 需显式指定数据源,而 watchEffect() 会自动追踪回调中的响应式依赖。

图示:响应式 API 之间的关系

代码实践:响应式数据与副作用监听

import { ref, reactive, computed, watch, watchEffect } from 'vue'; export default { setup() { // 1. ref 与 reactive const countRef = ref(0); const stateReactive = reactive({ name: 'Vue', version: 3 }); // 2. computed 计算属性 const price = ref(10); const quantity = ref(2); const totalPrice = computed(() => price.value * quantity.value); // 3. watch 精确监听 watch(countRef, (newValue, oldValue) => { console.log(`count changed: ${oldValue} -> ${newValue}`); }); // 4. watchEffect 自动追踪依赖 watchEffect(() => { console.log(`Total price is: ${totalPrice.value}`); }); return { countRef, stateReactive, price, quantity, totalPrice }; } };

watchwatchEffect 的核心区别:

  • 依赖收集watch 显式指定目标;watchEffect 自动收集回调内使用的响应式数据。
  • 执行时机watch 仅在数据变化时执行(默认懒执行);watchEffect 在初始化时会立即执行一次以收集依赖。

8.1.2.3 生命周期钩子:与 Options API 的映射关系

Composition API 提供了与 Options API 对应的生命周期钩子,需在 setup() 中显式导入,并统一使用 on 前缀。

Options API 生命周期钩子 Composition API 生命周期钩子
beforeCreate 不需要(setup() 本身即在此阶段执行)
created 不需要(setup() 本身即在此阶段执行)
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered
activated onActivated
deactivated onDeactivated
import { onMounted, onUpdated, onUnmounted } from 'vue'; export default { setup() { onMounted(() => { console.log('Component mounted'); // 执行 DOM 操作或发起网络请求 }); onUnmounted(() => { console.log('Component unmounted'); // 清理定时器、解绑全局事件监听器 }); } };

8.1.3 Composables:组合式函数的代码复用利器

Composables(组合式函数)是 Composition API 中实现逻辑复用的核心模式。它本质上是封装了可复用状态和逻辑的普通 JavaScript 函数,通常以 use 作为命名前缀。

图示:Composables 的复用模式

代码实践:封装鼠标位置追踪逻辑

// composables/useMousePosition.js import { ref, onMounted, onUnmounted } from 'vue'; export function useMousePosition() { const x = ref(0); const y = ref(0); function update(event) { x.value = event.pageX; y.value = event.pageY; } onMounted(() => window.addEventListener('mousemove', update)); onUnmounted(() => window.removeEventListener('mousemove', update)); return { x, y }; }
<!-- MyComponent.vue --> <template> <p>Mouse position: x: {{ x }}, y: {{ y }}</p> </template> <script> import { useMousePosition } from './composables/useMousePosition'; export default { setup() { const { x, y } = useMousePosition(); return { x, y }; } }; </script>

相比 Mixins,Composables 具有来源清晰无命名冲突支持参数传递以及完美的 TypeScript 支持等压倒性优势。

8.1.4 <script setup> 语法糖:极简开发体验

在 Vue 3.2 之后,官方引入了 <script setup> 编译时语法糖,这是使用 Composition API 的推荐标准写法。它极大地简化了代码结构,消除了手动 return 的繁琐。

核心优势:

  1. 更少的样板代码:顶层的变量、函数和导入的组件会自动暴露给模板,无需 return
  2. 更好的运行时性能:模板会被编译成与 <script setup> 在同一作用域内的渲染函数,避免了代理对象的开销。
  3. 更优的类型推断:对 TypeScript 和 IDE 的支持更加完善。
<script setup lang="ts"> import { ref, onMounted } from 'vue'; import MyButton from './MyButton.vue'; // 自动注册为组件 // 响应式状态 const count = ref(0); // 方法 const increment = () => { count.value++; }; // 生命周期 onMounted(() => { console.log('Component is mounted!'); }); </script> <template> <MyButton @click="increment"> Count is: {{ count }} </MyButton> </template>

8.1.5 Composition API 与 Options API 的共存与选型策略

Composition API 并非为了完全消灭 Options API,两者在 Vue 3 中可以完美共存

选型建议:

  • 小型/展示型组件:逻辑简单、状态极少,Options API 依然直观高效。
  • 大型/复杂业务组件:涉及多重状态流转、复杂副作用和逻辑复用,强烈建议使用 Composition API(配合 <script setup>)。
  • 团队规范:在中大型项目中,建议统一采用 <script setup> + Composition API 的标准,降低心智负担,避免代码风格割裂。
<script> import { ref } from 'vue'; export default { // Options API 部分 data() { return { optionsCount: 0 }; }, methods: { incrementOptions() { this.optionsCount++; } }, // Composition API 部分 setup() { const compositionCount = ref(0); const incrementComposition = () => { compositionCount.value++; }; return { compositionCount, incrementComposition }; } }; </script>

注:虽然支持混用,但在实际工程中应避免在同一组件内混合使用,以保持代码一致性。

8.1.6 总结与最佳实践展望

Composition API 是 Vue 3 架构演进中的里程碑。通过 setup() 函数、响应式系统和 Composables,它彻底解决了 Options API 在复杂场景下的逻辑碎片化和复用难题。

核心收益总结:

  1. 高内聚低耦合:业务逻辑按功能聚合,而非按配置项分散。
  2. 极致的复用能力:通过 Composables 实现无副作用、清晰的逻辑抽离。
  3. TypeScript 原生友好:告别复杂的 this 类型推断,拥抱静态类型安全。

随着 Vue 生态的全面升级,掌握 Composition API 及 <script setup> 已成为现代前端开发者的必备技能。在未来的项目实践中,合理拆分 Composables、遵循单一职责原则、善用 TypeScript,将帮助团队构建出更加健壮、易维护的企业级 Vue.js 应用。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U