当前位置: 首页 > news >正文

Vue 3组合式函数实战:从原理到项目架构与性能优化

1. 从“选项式”到“组合式”:为什么我们需要组合式函数?

如果你是从 Vue 2 时代一路走来的开发者,或者刚刚接触 Vue 3,你可能会对“组合式函数”这个概念感到既熟悉又陌生。熟悉的是,它似乎和 Vue 2 里的mixins有些相似,都是为了复用逻辑;陌生的是,它的写法、理念和带来的可能性,又完全是另一番天地。

简单来说,组合式函数 (Composables)是 Vue 3 组合式 API 的“灵魂伴侣”。它不是一个内置的 API,而是一种基于组合式 API 来封装和复用有状态逻辑的代码组织模式。你可以把它理解为一个自定义的、可复用的“逻辑积木”。在选项式 API 中,我们的逻辑被分散在datamethodscomputedwatch这些固定的选项中,当组件复杂时,追踪一个功能的完整逻辑需要上下翻找。而组合式函数,则允许我们将一个功能相关的所有逻辑(响应式状态、计算属性、方法、副作用等)集中封装在一个函数里,然后在组件中像搭积木一样“组合”使用。

为什么这种模式在今天变得如此重要?看看那些热搜词就知道了:vue项目实战vue封装组件库vue项目性能优化。现代前端应用越来越复杂,不再是简单的几个页面。一个中后台管理系统(如热搜中的ruoyi vue pro基于springboot与vue的图书借阅管理系统)可能包含数十上百个组件,其中充斥着大量重复的业务逻辑,比如表单验证、数据获取、模态框控制、全局状态共享等。如果每个组件都从头写一遍,不仅代码冗余,维护起来更是噩梦。mixins曾试图解决这个问题,但它带来了命名冲突、来源不清晰、难以追踪等新问题。组合式函数,正是在这样的背景下,作为mixins的现代化、更优的替代方案被广泛采纳。

它的核心价值在于:让关注点分离,而不是技术栈分离。在组合式函数中,一个功能的所有代码都在一起,自包含、自描述。当你在vue面试题中被问到如何组织复杂逻辑时,组合式函数是一个极具说服力的答案。它让我们的代码更易于阅读、测试和复用,是构建可维护的大型vue项目的基石。

2. 解剖一个组合式函数:从“获取鼠标位置”开始

理论说再多,不如亲手写一个。我们从一个经典的、几乎在所有教程里都会出现的例子开始:创建一个追踪鼠标位置的组合式函数。这个例子虽小,但能完整展示组合式函数的全部要素。

2.1 基础实现:响应式状态与副作用

首先,我们创建一个名为useMouse的文件(通常以use开头,这是一种约定俗成的命名方式)。

// useMouse.js import { ref, onMounted, onUnmounted } from 'vue' export function useMouse() { // 1. 定义响应式状态 const x = ref(0) const y = ref(0) // 2. 定义更新状态的函数 function update(event) { x.value = event.pageX y.value = event.pageY } // 3. 在组件挂载时设置事件监听器(副作用) onMounted(() => window.addEventListener('mousemove', update)) // 4. 在组件卸载时清理副作用 onUnmounted(() => window.removeEventListener('mousemove', update)) // 5. 返回状态(和方法),供组件使用 return { x, y } }

现在,让我们在组件中使用它:

<template> <div>鼠标位置:{{ x }}, {{ y }}</div> </template> <script setup> import { useMouse } from './useMouse.js' const { x, y } = useMouse() </script>

看,多么清晰!组件本身不再关心如何监听鼠标事件、如何更新状态、如何清理。它只是“使用”了useMouse这个逻辑单元,并消费其返回的状态。这正是组合式的精髓:将逻辑提取为独立的、可复用的函数

2.2 进阶思考:参数化与灵活性

基础的useMouse很好,但不够灵活。如果我想监听的不是window,而是某个特定的 DOM 元素呢?我们可以通过参数化来增强它。

// useMouseInElement.js import { ref, onMounted, onUnmounted } from 'vue' export function useMouseInElement(target) { const x = ref(0) const y = ref(0) function update(event) { // 计算相对于目标元素的位置 const rect = target.getBoundingClientRect() x.value = event.clientX - rect.left y.value = event.clientY - rect.top } onMounted(() => target.addEventListener('mousemove', update)) onUnmounted(() => target.removeEventListener('mousemove', update)) return { x, y } }

在组件中使用时,我们需要传递一个 DOM 元素引用。这里就用到了 Vue 的模板引用 (ref)

<template> <div ref="boxRef" style="width: 300px; height: 200px; border: 1px solid #ccc;"> 鼠标在此区域的位置:{{ x }}, {{ y }} </div> </template> <script setup> import { ref } from 'vue' import { useMouseInElement } from './useMouseInElement.js' const boxRef = ref(null) // 注意:需要在元素挂载后调用,可以使用 watchEffect 或 onMounted const { x, y } = useMouseInElement(boxRef.value) // 这样写有问题! </script>

这里引出了一个组合式函数使用中的关键细节执行时机。上面的写法有问题,因为在script setup执行时,boxRef.value还是null(DOM 尚未渲染)。正确的做法是使用watchEffect或确保在组件挂载后调用。

import { ref, watchEffect } from 'vue' import { useMouseInElement } from './useMouseInElement.js' const boxRef = ref(null) let mouseState = { x: ref(0), y: ref(0) } watchEffect(() => { if (boxRef.value) { // 当 boxRef 有值时,重新执行并建立新的监听 const result = useMouseInElement(boxRef.value) // 这里需要处理返回值的覆盖问题,更复杂的场景可能需要自定义 hook 来管理 mouseState = result } })

这个例子告诉我们,设计组合式函数时,需要考虑其与组件生命周期的耦合关系。一个更健壮的useMouseInElement可能会内部处理这些细节,或者明确要求使用者传入一个Ref<HTMLElement>,然后在内部用watch来响应变化。

3. 组合式函数的实战场景:超越玩具示例

“获取鼠标位置”只是一个教学示例。在实际的vue项目实战中,组合式函数大放异彩的地方在于封装业务逻辑。让我们结合热搜词中的一些场景,看看它如何解决真实问题。

3.1 场景一:数据获取与状态管理(替代 Vuex 模块?)

热搜词里有vue获取短信验证码vue springboot sqlserver。这背后是典型的数据获取逻辑。我们常会写一个useUserAPIuseAuth的组合式函数。

// useAuth.js import { ref } from 'vue' import axios from 'axios' // 或你喜欢的请求库 export function useAuth() { const user = ref(null) const loading = ref(false) const error = ref(null) async function login(credentials) { loading.value = true error.value = null try { const response = await axios.post('/api/login', credentials) user.value = response.data // 可能还会设置 token 到 localStorage 或 cookie localStorage.setItem('token', response.data.token) } catch (err) { error.value = err.message || '登录失败' } finally { loading.value = false } } function logout() { user.value = null localStorage.removeItem('token') } // 可以添加自动检查登录状态、刷新 token 等逻辑 return { user, loading, error, login, logout, } }

在任何一个需要认证的组件中,你都可以直接使用:

<script setup> import { useAuth } from '@/composables/useAuth' const { user, loading, error, login } = useAuth() const form = ref({ username: '', password: '', }) async function handleSubmit() { await login(form.value) if (user.value) { // 登录成功,跳转... } } </script>

这种模式将所有的认证状态和逻辑集中在一处,比分散在多个组件的datamethods中要清晰得多。对于中小型应用,你甚至可以用一系列这样的组合式函数来管理全局状态,替代部分 Vuex/Pinia 的模块。当然,对于非常复杂的状态交互,专业的状态库仍然是更好的选择。

3.2 场景二:通用 UI 逻辑封装(模态框、下拉菜单)

热搜词vue封装组件库提示了这一点。组件库的底层是基础组件,而上层是业务组件。组合式函数可以帮助我们封装那些与 UI 交互紧密相关但无渲染的逻辑。

例如,一个控制下拉菜单显示/隐藏的useDropdown

// useDropdown.js import { ref, onMounted, onUnmounted } from 'vue' export function useDropdown(triggerRef, dropdownRef) { const isOpen = ref(false) function open() { isOpen.value = true } function close() { isOpen.value = false } function toggle() { isOpen.value = !isOpen.value } function handleClickOutside(event) { if ( dropdownRef.value && !dropdownRef.value.contains(event.target) && triggerRef.value && !triggerRef.value.contains(event.target) ) { close() } } onMounted(() => { document.addEventListener('click', handleClickOutside) }) onUnmounted(() => { document.removeEventListener('click', handleClickOutside) }) return { isOpen, open, close, toggle, } }

这样,你的下拉菜单组件只需要关注渲染,交互逻辑全部由useDropdown接管:

<template> <div> <button ref="triggerRef" @click="toggle">菜单</button> <div v-show="isOpen" ref="dropdownRef" class="dropdown-content"> <!-- 菜单内容 --> </div> </div> </template> <script setup> import { ref } from 'vue' import { useDropdown } from './useDropdown' const triggerRef = ref(null) const dropdownRef = ref(null) const { isOpen, toggle } = useDropdown(triggerRef, dropdownRef) </script>

这种模式极大地提升了逻辑的复用性。你可以用同样的模式封装useModaluseTooltipuseDraggable等,这些都是构建自己的vue封装组件库时的利器。

3.3 场景三:集成第三方库

热搜词中有amchart vue用在vue里的腾讯地图。将第三方库集成到 Vue 中,并管理其生命周期和响应式状态,是组合式函数的绝佳场景。

以集成一个图表库为例:

// useChart.js import { ref, onMounted, onUnmounted, watch } from 'vue' import * as am5 from '@amcharts/amcharts5' import am5themes_Animated from '@amcharts/amcharts5/themes/Animated' export function useChart(containerRef, chartConfig) { const chart = ref(null) const root = ref(null) onMounted(() => { // 创建根和图表 root.value = am5.Root.new(containerRef.value) root.value.setThemes([am5themes_Animated.new(root.value)]) chart.value = root.value.container.children.push( am5.XYChart.new(root.value, chartConfig) ) // 这里可以根据传入的 config 配置序列、轴等 // ... }) // 监听配置变化,更新图表 watch( () => chartConfig, (newConfig) => { if (chart.value) { // 应用新的配置到现有图表 // 注意:这里需要根据具体库的API进行更新,可能是销毁重建或动态更新 } }, { deep: true } ) onUnmounted(() => { if (root.value) { root.value.dispose() } }) return { chart, root, } }

在组件中使用:

<template> <div ref="chartContainer" style="width: 100%; height: 400px;"></div> </template> <script setup> import { ref } from 'vue' import { useChart } from './useChart' const chartContainer = ref(null) const chartConfig = ref({ // ... 你的图表配置 }) const { chart } = useChart(chartContainer, chartConfig) // 之后可以通过 chart.value 来调用图表实例的方法 </script>

这个组合式函数处理了第三方库的初始化、配置响应式更新以及最重要的——资源清理(在onUnmounted中调用dispose)。这避免了内存泄漏,是很多开发者在集成第三方库时容易忽略的坑(参考热搜vue项目性能优化)。

4. 组合式函数的最佳实践与高级模式

掌握了基础用法和常见场景后,我们来深入探讨一些最佳实践和高级模式,这些能让你写出的组合式函数更健壮、更优雅。

4.1 返回值:灵活性与约定

组合式函数可以返回任何东西,但最常见的模式是返回一个包含多个ref和函数的对象。为了支持在组件中的解构赋值,同时保持响应性,返回的对象通常是普通对象,其属性是ref

// 返回响应式对象 return { data: ref(null), loading: ref(false), error: ref(null), fetchData, }

有时,你可能希望返回一个reactive对象,这样在组件中可以直接通过.访问属性,而无需.value。但这会失去解构赋值时的响应性(除非使用toRefs)。

import { reactive, toRefs } from 'vue' export function useFeature() { const state = reactive({ count: 0, name: 'Vue', }) function increment() { state.count++ } // 返回 toRefs 后的对象,可以在解构后保持响应性 return { ...toRefs(state), increment, } }

实操心得:我个人更倾向于返回普通对象,里面包含多个ref。这样在组件中使用解构语法const { data, loading } = useXXX()非常直观,且每个变量都是独立的ref,心智负担小。只有在状态属性非常多且紧密相关时,才会考虑使用reactive+toRefs的模式。

4.2 副作用与生命周期:清晰的职责边界

组合式函数内部可以调用生命周期钩子,如onMounted,onUnmounted,onUpdated等。这是其强大之处,但也需要谨慎。

  • 自动清理:如果组合式函数设置了副作用(如事件监听器、定时器、订阅),必须onUnmounted中清理。这是防止内存泄漏的铁律。
  • 执行时机:组合式函数在setup()<script setup>中被同步调用。其内部的onMounted钩子会被排队,并在组件挂载时执行。这意味着你可以在组合式函数内部安全地访问 DOM(如果操作依赖于已挂载的元素)。
  • 条件调用:组合式函数本身应该被无条件调用。如果你需要根据条件来运行某些逻辑,应该将条件判断放在组合式函数内部,或者使用watchEffect/watch来响应式地执行。
// 不推荐:在组件中条件性调用 hook if (someCondition) { const result = useSomeHook() // 这可能导致 hook 内部生命周期钩子的注册混乱 } // 推荐:在 hook 内部处理条件逻辑 export function useConditionalHook(someConditionRef) { onMounted(() => { if (someConditionRef.value) { // 执行逻辑 } }) }

4.3 依赖注入:提供更灵活的配置

组合式函数可以接受参数来定制其行为。参数可以是静态值,也可以是ref,使其变成响应式的。

export function useFetch(urlRef, options = {}) { const data = ref(null) const error = ref(null) const loading = ref(false) async function doFetch() { // ... 使用 urlRef.value 进行获取 } // 如果 urlRef 是 ref,可以 watch 它 watch(urlRef, doFetch, { immediate: true }) return { data, error, loading, doFetch } }

更高级的模式是,利用 Vue 的provideinject,在组合式函数内部注入依赖。例如,一个useApi组合式函数可以注入基础的axios实例或 API 端点配置。

// 在应用顶层提供配置 // app.js import { createApp } from 'vue' import { createApi } from './api' const app = createApp(App) const api = createApi({ baseURL: '/api' }) app.provide('api', api) // useApi.js import { inject } from 'vue' export function useApi(endpoint) { const api = inject('api') // 获取注入的 API 实例 // ... 使用 api 进行请求 }

这种方式使得组合式函数不直接依赖具体的模块,提高了可测试性和可配置性,在大型vue项目或构建vue后端管理框架时非常有用。

4.4 测试组合式函数

可测试性是组合式函数的另一大优势。由于它本质上是一个纯函数(接收参数,返回值和函数),测试起来比测试一个完整的、带有生命周期的组件要简单得多。

你可以使用@vue/test-utilsvitest/jest来测试。

// useCounter.test.js import { renderHook } from '@testing-library/vue' // 或类似的测试工具 import { useCounter } from './useCounter' describe('useCounter', () => { it('should increment count', () => { const { result } = renderHook(() => useCounter()) expect(result.count.value).toBe(0) result.increment() expect(result.count.value).toBe(1) }) it('should accept initial count', () => { const { result } = renderHook(() => useCounter(5)) expect(result.count.value).toBe(5) }) })

测试的关键是模拟生命周期和响应式环境。一些测试库提供了renderHook这样的工具来简化这个过程。

5. 组合式函数 vs. Mixins vs. 工具函数:如何选择?

在组合式函数出现之前,我们主要有两种逻辑复用方式:Mixins工具函数/工具类。理解它们的区别,能帮助我们在正确的场景选择正确的工具。

5.1 与 Mixins 的对比

这是最常被问到的问题。Mixins 在 Vue 2 中广泛使用,但存在以下痛点:

  1. 命名冲突:多个 mixin 可能定义同名的数据或方法,后引入的会覆盖先引入的,调试困难。
  2. 来源模糊:在组件中使用一个属性时,很难一眼看出它来自哪个 mixin。
  3. 隐式依赖:mixin 可能依赖特定的组件选项或全局状态,形成“暗箱操作”,难以理解和重构。
  4. 可组合性差:多个 mixin 交互时,行为可能不可预测。

组合式函数解决了所有这些问题:

  • 显式导入:你需要什么就导入什么,来源清晰。
  • 命名灵活:在组件中可以通过解构重命名,避免冲突。
  • 依赖明确:组合式函数的参数和返回值都是明确的,没有隐式依赖。
  • 自由组合:你可以像搭积木一样组合多个组合式函数,它们彼此独立。

踩坑实录:我曾维护过一个大型 Vue 2 项目,其中使用了超过 10 个 mixin。追踪一个handleSubmit方法的来源就像侦探破案,需要依次检查所有 mixin 的文件。迁移到 Vue 3 的组合式函数后,每个功能逻辑都被封装在独立的useXXX文件中,在组件顶部一目了然,维护效率提升了不止一个量级。

5.2 与工具函数的对比

工具函数(Utility Functions)是纯函数,无状态,只进行计算或操作。例如一个格式化日期的函数formatDate(date)

  • 工具函数:封装无状态的逻辑。输入确定,输出就确定。适合格式化、验证、计算等。
  • 组合式函数:封装有状态的逻辑。它内部管理着响应式状态(ref,reactive)和生命周期副作用。适合与组件状态和生命周期紧密相关的逻辑。

简单判断准则:如果你的逻辑需要用到refreactivecomputedwatch或生命周期钩子,那么它应该是一个组合式函数。如果只是对输入数据进行转换或计算,那么它就是一个工具函数。

在实际项目中,它们常常协同工作。一个组合式函数内部可能会调用多个工具函数。

// 工具函数 export function calculateDiscount(price, discountRate) { return price * (1 - discountRate) } // 组合式函数 export function useShoppingCart() { const items = ref([]) const discountRate = ref(0.1) const totalPrice = computed(() => { return items.value.reduce((sum, item) => sum + item.price, 0) }) const finalPrice = computed(() => { // 组合式函数内部调用工具函数 return calculateDiscount(totalPrice.value, discountRate.value) }) return { items, discountRate, totalPrice, finalPrice } }

6. 在大型项目中架构组合式函数

当项目规模增长,像热搜中提到的ruoyi vue pro(芋道) mall 商城模块java + vue 自动化agent平台这类系统,组合式函数的组织和架构就变得至关重要。

6.1 目录结构

一个清晰的结构有助于团队协作和代码查找。常见的做法是在src目录下建立composables文件夹。

src/ ├── composables/ │ ├── index.js // 可选:统一导出 │ ├── useFetch.js // 通用的数据获取 │ ├── useForm.js // 表单处理逻辑 │ ├── usePagination.js // 分页逻辑 │ ├── useModal.js // 模态框控制 │ ├── auth/ // 按领域分目录 │ │ ├── useAuth.js │ │ └── usePermission.js │ ├── cart/ // 购物车相关 │ │ └── useCart.js │ └── product/ // 商品相关 │ └── useProductSearch.js ├── components/ └── views/

index.js中统一导出,方便引用:

// composables/index.js export { useFetch } from './useFetch' export { useAuth } from './auth/useAuth' // ...

6.2 分层设计:基础层、领域层、业务层

借鉴后端架构思想,可以对组合式函数进行分层:

  1. 基础层 (Foundation Layer):与 UI/框架无关或关系很小的纯逻辑。例如useEventListeneruseIntervaluseLocalStorage。这些函数高度可复用,甚至可以抽离成独立的工具库。
  2. 领域层 (Domain Layer):封装特定业务领域的逻辑。例如useAuthuseCartuseProduct。它们会使用基础层的组合式函数,并包含业务规则和状态。
  3. 业务层 (Business Layer / Component-specific Composables):为特定页面或组件量身定制的组合式函数。它们可能组合多个领域层的函数,并添加一些页面特有的状态和逻辑。这类函数复用性可能较低,但能极大保持组件本身的简洁。

这种分层确保了关注点分离,基础层稳定,领域层清晰,业务层灵活。

6.3 状态共享与跨组件通信

组合式函数本身是函数调用,每次调用都会创建新的响应式状态。如果需要在多个组件间共享状态,有几种模式:

  • 状态提升:将状态定义在共同的父组件,通过 props 传递,或使用provide/inject
  • 使用状态管理库:对于复杂的全局状态(如用户信息、购物车),使用 Pinia(Vue 官方推荐)或 Vuex 仍然是更专业的选择。你可以在组合式函数内部使用 Pinia store。
  • 单例模式:通过模块作用域创建一个响应式状态,并在组合式函数中返回对它的引用。需极度谨慎,因为这本质上是全局变量,可能带来测试和并发问题。
// 谨慎使用:模块作用域状态 const globalState = ref(0) export function useSharedState() { // 直接返回对全局状态的引用 function increment() { globalState.value++ } return { state: globalState, increment, } } // 组件A和组件B调用 useSharedState() 将操作同一个 state

在大多数情况下,对于需要跨组件共享的业务状态,优先考虑使用 Pinia。组合式函数更适合封装无共享需求的、或以依赖注入方式共享的逻辑。

7. 常见陷阱与性能考量

即使掌握了模式,在实际编码中还是会遇到一些坑。结合vue项目性能优化这个热搜,我们来谈谈组合式函数相关的性能与陷阱。

7.1 重复创建与内存泄漏

这是最容易出错的地方。如果一个组合式函数内部创建了事件监听器、定时器或订阅,但清理不彻底,就会导致内存泄漏。

黄金法则:有onMounted/onUnmounted添加副作用,就必须有对应的清理。

// 错误示例:忘记清理 export function useInterval(callback, delay) { onMounted(() => { setInterval(callback, delay) // 定时器ID没有保存,无法清理 }) // 缺少 onUnmounted } // 正确示例 export function useInterval(callback, delay) { let intervalId = null onMounted(() => { intervalId = setInterval(callback, delay) }) onUnmounted(() => { if (intervalId) clearInterval(intervalId) }) // 还可以提供手动停止/重启的方法 function stop() { clearInterval(intervalId) } function start() { intervalId = setInterval(callback, delay) } return { stop, start } }

7.2 响应式依赖与无限循环

在组合式函数内部使用watchcomputed时,如果依赖项设置不当,可能导致无限更新循环。

export function useSomeLogic(dataRef) { const processedData = computed(() => { // 对 dataRef.value 进行一些处理... return heavyTransform(dataRef.value) }) // 危险:如果 processedData 被用于更新 dataRef,就会循环 watch(processedData, (newVal) => { // 假设这里又去修改了 dataRef... // dataRef.value = newVal + 'something'; // 这将触发 computed 重新计算,进而再次触发 watch... }) }

排查思路:使用开发工具(如vue devtools)观察组件的更新次数。如果某个computedwatch在极短时间内被疯狂触发,很可能陷入了循环。仔细检查响应式依赖链。

7.3 昂贵的计算与优化

组合式函数中的computed属性如果执行开销很大,且其依赖的响应式数据频繁变化,可能会成为性能瓶颈。

优化策略

  1. 使用computed的缓存特性:确保computed只在其依赖项实际变化时才重新计算。
  2. 惰性计算:对于非立即需要的昂贵计算,可以使用watchEffectwatch配合标志位,或者使用shallowRef手动控制更新时机。
  3. 使用watchflush选项watch默认是组件更新后执行 (flush: 'post')。对于某些需要在 DOM 更新前同步执行的操作,可以设置为flush: 'sync',但要小心使用,避免过度更新。
export function useExpensiveOperation(listRef) { // 假设 heavyComputation 非常耗时 const result = computed(() => heavyComputation(listRef.value)) // 如果 listRef 频繁变化,但结果不需要实时同步,可以防抖 const debouncedResult = ref(null) const debounceWatch = watch( listRef, (newList) => { // 使用防抖逻辑,例如 lodash 的 debounce debouncedResult.value = heavyComputation(newList) }, { deep: true } ) return { result, debouncedResult } }

7.4 在 SSR 中的使用

如果你的vue项目是服务端渲染(SSR)的(如使用 Nuxt.js),需要特别注意组合式函数的编写。因为 SSR 环境下没有windowdocument等浏览器 API,也没有组件挂载的生命周期。

解决方案

  • 条件执行:使用import.meta.env.SSRprocess.server(Nuxt)判断环境。
  • 生命周期钩子onMountedonUnmounted等只在客户端执行。可以将依赖浏览器 API 的代码放在这些钩子里,或者用条件判断包裹。
  • 状态共享:确保在 SSR 和客户端激活(hydration)时,组合式函数产生的初始状态是一致的,否则会导致激活不匹配错误。
import { onMounted, ref } from 'vue' export function useLocalStorage(key) { const value = ref(null) if (!import.meta.env.SSR) { // 仅在客户端读取 localStorage value.value = localStorage.getItem(key) onMounted(() => { // 或者在这里读取 }) } // ... 其他逻辑 return { value } }

组合式函数是 Vue 3 组合式 API 哲学的核心体现。它不仅仅是一个代码组织工具,更是一种推动我们走向更清晰、更可维护、更可测试的前端架构的思维方式。从简单的鼠标跟踪到复杂的业务逻辑集成,它提供了一种统一而强大的抽象模式。刚开始可能需要一些思维转换,但一旦习惯,你会发现它能让你的vue项目代码质量提升一个档次,尤其是在应对vue面试题中关于代码组织和复用的提问时,你将拥有一个非常有力的答案。记住,多写、多重构、多思考“这段逻辑能否抽出去”,是掌握组合式函数的最佳路径。

http://www.jsqmd.com/news/1383715/

相关文章:

  • AI记忆系统构建指南:从短期记忆到长期记忆与智能体工作记忆
  • 2026高速伺服电机厂家选型指南:杭州摩森机电技术优势解析 - 品牌报告
  • DownKyi终极指南:B站视频下载工具的法律风险与合法替代方案
  • 2026年淮安废铝回收电话精选:三个步骤教你避开回收陷阱,轻松卖高价 - geo交流
  • 企业智能体开发怎么做?从需求分析、业务语义层到生产上线的10个关键步骤
  • 终极Windows右键菜单管理方案:ContextMenuManager完全指南
  • 突破操作系统隐形瓶颈:TCP窗口、QoS与中断合并优化实战
  • aixingpan.cn API开发文档:api_docs_trichart_natal_lunar_return_transit2接口指南
  • GitHub Models退役:AI模型托管迁移与Hugging Face/ModelScope实践指南
  • 非小米电脑安装小米妙享中心:绕过机型认证的两种技术方案
  • 天同天梁在寅申:福星与荫星的深层互动与人生调和
  • 2026年梅州充电桩机组回收优选指南:哪些推荐方案更靠谱? - geo交流
  • Node.js构建高并发民宿管理系统的实战经验
  • AI模型集成实战:构建面向网络防御的威胁情报分析原型
  • 硬件工程师必知:17种核心PCB封装设计要点与避坑指南
  • GitHub汉化插件:5分钟让GitHub界面说中文的完整解决方案
  • 揭秘大模型回复生成:从概率游戏到采编审校的完整流程
  • 开源AI模型入门:从环境搭建到本地部署的实践指南
  • RAG技术实战:从零构建本地知识库问答系统
  • PyQt5从安装到打包:Python桌面应用开发全攻略
  • 从外挂到内置:探索大语言模型记忆内化的技术路径与挑战
  • 2026年兰州榆中县超市拆除回收电话甄选清单:从咨询到上门一站搞定 - geo交流
  • 知识蒸馏规模化实践:从离线蒸馏到工程优化的低成本解决方案
  • 如何5分钟快速上手C++编程:小熊猫Dev-C++的完整入门指南
  • AI编程时代:从代码生成到系统架构,工程师如何转型为AI增强型开发者
  • Gmail注册实战指南:从环境准备到安全设置的完整流程解析
  • 全国340万AOI数据集解析与应用实践
  • 从零实现Transformer:自注意力机制与PyTorch实战详解
  • TS格式深度解析:从音视频传输流到TypeScript类型系统的跨界实战
  • NAND Flash协议与时序深度解析:从接口原理到实战调试