Composables和Utils的区别(自学用)

一句话总结核心区别:

  • Utils(工具函数)纯数据 / 逻辑处理,无状态、无 Vue 特性,通用、可在任何框架 / 无框架使用。
  • Composables(组合式函数)Vue 专属的状态化逻辑封装,依赖 Vue API(ref/reactive/watch 等),带响应式状态、生命周期,只能在 Vue 组件 / 其他 Composables 中使用。

一、Utils(工具函数)详解

1. 定义

utils通用工具函数 ,本质是纯函数(优先) ,用来封装与框架无关的通用逻辑,只负责「输入 → 处理 → 输出」,不依赖任何前端框架(Vue/React/ 原生 JS 都能用)。

2. 核心特点

  1. 无 Vue 依赖 :不使用 ref/reactive/watch/ 生命周期等任何 Vue API
  2. 无状态 / 无副作用:相同输入永远返回相同输出,不修改外部变量
  3. 通用性极强:可在 Vue 组件、JS 文件、Node.js 中任意调用
  4. 轻量、独立:一个函数只做一件事(格式化、计算、校验等)

3. 适用场景

  • 数据格式化(时间、金额、手机号)
  • 字符串 / 数组 / 对象操作
  • 表单校验、数学计算
  • 本地存储封装(简单版)、通用常量

4. 代码示例

Javascript

js 复制代码
// src/utils/format.js
// 纯工具函数:和 Vue 无关,任何项目都能用
export function formatMoney(num) {
  if (isNaN(num)) return '0.00'
  return Number(num).toFixed(2)
}

export function formatDate(timestamp) {
  const date = new Date(timestamp)
  return date.toLocaleDateString()
}

TypeScript

ts 复制代码
// src/utils/format.ts
// 纯工具函数:和 Vue 无关,任何项目都能用

/**
 * 格式化金额(保留两位小数)
 * @param num - 数字或数字字符串
 * @returns 格式化后的金额字符串
 */
export function formatMoney(num: number | string): string {
  const n = typeof num === 'string' ? parseFloat(num) : num
  if (isNaN(n)) return '0.00'
  return n.toFixed(2)
}

/**
 * 格式化时间戳为本地日期字符串
 * @param timestamp - 毫秒时间戳
 * @returns 格式化后的日期字符串
 */
export function formatDate(timestamp: number): string {
  const date = new Date(timestamp)
  return date.toLocaleDateString()
}

5. 使用方式

Javascript

js 复制代码
<script setup>
    // 直接调用,无需关心生命周期、响应式
    import { formatMoney } from '@/utils/format'

    const price = 99
    console.log(formatMoney(price)) // 99.00
</script>

TypeScript

ts 复制代码
<script setup lang="ts">
    import { formatMoney } from '@/utils/format'

    const price = 99
    console.log(formatMoney(price)) // "99.00"
</script>

二、Composables(组合式函数)详解

1. 定义

composablesVue 组合式函数 ,专门用来封装带 Vue 响应式 / 生命周期的复用逻辑,是 Vue 3 组合式 API 的核心实践。

命名规范:必须以 use开头 (如 useUseruseWindowSize)。

2. 核心特点

  1. 强依赖 Vue :必须使用 Vue 提供的 API(ref/reactive/watch/onMounted 等)
  2. 自带响应式状态:内部管理响应式数据,可被组件共享、追踪变化
  3. 绑定 Vue 生命周期:能监听组件挂载、卸载,处理副作用
  4. 组件专属 :只能在 <script setup> 或其他 Composables 中使用
  5. 逻辑聚合:把「数据 + 方法 + 监听」打包复用

3. 适用场景

  • 响应式数据逻辑(窗口大小、滚动位置、计时器)
  • 业务状态共享(用户信息、购物车、表单状态)
  • 生命周期副作用(定时器、事件监听、接口轮询)
  • 跨组件复用的 Vue 专属逻辑

4. 代码示例

Javascript

js 复制代码
// src/composables/useWindowSize.js
// Vue 专属组合式函数:依赖响应式 + 生命周期
import { ref, onMounted, onUnmounted } from 'vue'

export function useWindowSize() {
  // 响应式状态(Vue API)
  const width = ref(window.innerWidth)
  const height = ref(window.innerHeight)

  // 事件处理函数
  function updateSize() {
    width.value = window.innerWidth
    height.value = window.innerHeight
  }

  // 绑定 Vue 生命周期
  onMounted(() => window.addEventListener('resize', updateSize))
  onUnmounted(() => window.removeEventListener('resize', updateSize))

  // 返回响应式状态和方法
  return { width, height }
}

TypeScript

ts 复制代码
// src/composables/useWindowSize.ts
// Vue 专属组合式函数:依赖响应式 + 生命周期
import { ref, onMounted, onUnmounted, type Ref } from 'vue'

interface WindowSize {
  width: Ref<number>
  height: Ref<number>
}

export function useWindowSize(): WindowSize {
  // 响应式状态(Vue API)
  const width = ref<number>(window.innerWidth)
  const height = ref<number>(window.innerHeight)

  // 事件处理函数
  function updateSize(): void {
    width.value = window.innerWidth
    height.value = window.innerHeight
  }

  // 绑定 Vue 生命周期
  onMounted(() => window.addEventListener('resize', updateSize))
  onUnmounted(() => window.removeEventListener('resize', updateSize))

  // 返回响应式状态
  return { width, height }
}

5. 使用方式

Javascript

js 复制代码
<script setup>
// 直接使用响应式数据,自动跟随变化
import { useWindowSize } from '@/composables/useWindowSize'
const { width, height } = useWindowSize()
</script>

<template>
  <div>窗口宽度:{{ width }}</div>
  <div>窗口高度:{{ height }}</div>
</template>

TypeScript

ts 复制代码
<script setup lang="ts">
import { useWindowSize } from '@/composables/useWindowSize'

const { width, height } = useWindowSize()
</script>

<template>
  <div>窗口宽度:{{ width }}</div>
  <div>窗口高度:{{ height }}</div>
</template>

三、Composables 和 Utils 核心区别对比表

维度 Utils(工具函数) Composables(组合式函数)
依赖 无框架依赖,纯 JS 强依赖 Vue 3 组合式 API
状态 无状态、纯函数 响应式状态,可管理数据
生命周期 无关,不依赖组件生命周期 可使用 onMounted 等 Vue 生命周期
复用范围 全场景通用(Vue/React/Node/ 原生 JS) 仅 Vue 组件 / 其他 Composables 中使用
核心作用 数据处理、工具方法 封装带响应式的业务逻辑、组件逻辑复用
命名 随意(camelCase) 强制 useXxx 开头
例子 formatMoneydebouncevalidatePhone useUseruseWindowSizeuseForm

四、最简单的区分方法

  1. 如果逻辑里用到了 ref/reactive/watch/onMounted → 一定放在 composables
  2. 如果只是纯数据计算、格式化、通用方法 → 一定放在 utils
  3. Composables 可以调用 Utils,但 Utils 绝对不能调用 Composables(工具不能依赖框架)

五、标准项目目录结构

plaintext

plain 复制代码
src/
├── composables/  # Vue 组合式函数(响应式、生命周期)
│   ├── useUser.js
│   ├── useWindowSize.js
│   └── useCart.js
├── utils/        # 通用工具函数(纯 JS、无状态)
│   ├── format.js
│   ├── validate.js
│   └── common.js

总结

  1. Utils = 通用工具,纯 JS,无状态,哪里都能用
  2. Composables = Vue 逻辑复用,带响应式 + 生命周期,只能在 Vue 中用
  3. 区分关键:是否使用 Vue API、是否需要响应式状态
相关推荐
kyriewen7 小时前
别再 console.log 了:5 个 Chrome DevTools 调试技巧,用过就回不去了
前端·javascript·面试
IT_陈寒9 小时前
Python搞不定字符串编码?这破玩意坑我两小时!
前端·人工智能·后端
DigitalOcean10 小时前
Laravel 开发者已在 DigitalOcean 上开通超过 10 万台服务器
前端·laravel
星始流年10 小时前
从 Tool 到 Skill——基于 LangChain 的服务端Skill实现
前端·langchain·agent
李惟10 小时前
开源本地通信库,纯客户端 RPC,像聊天一样通信
前端
YAwu1110 小时前
深入解析 React 炫彩鼠标跟随标题组件:从坐标定位到动画性能
前端·react.js
GuWenyue10 小时前
排序效率低?5分钟吃透快速排序,性能飙升至O(nlogn)
前端·javascript·面试
OpenTiny社区10 小时前
🎨 看完 GenUI SDK 源码我悟了!
前端·vue.js·github
叁两10 小时前
前端转型AI Agent该如何学习?(前置篇)
前端·人工智能·node.js
何时梦醒10 小时前
深入理解递归与快速排序 —— 从基础入门到手写实现
前端·javascript