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、是否需要响应式状态
相关推荐
kungggyoyoyo1 小时前
从0开发一套geo优化软件:系统定位与整体架构
前端
用户713874229001 小时前
PKCE 的 S256 算法深度剖析:从协议设计到密码学原理
前端
闪闪发光得欧1 小时前
StreamTokenizer的源码分析和使用方法详细分析
前端
李剑一1 小时前
华为一面就问网络安全?面试官:请简述一下 XSS/CSRF 的攻击面与前端侧的防护
前端·面试
竹林8181 小时前
被合约事件搞到失眠?我踩了三天坑,终于写出一份监听智能合约事件的实战指南
前端·javascript
用户059540174461 小时前
把 AI 记忆验证从手工 Log 换成 Pytest+Mem0,上下文丢失 bug 减少 90%
前端·css
艾利克斯冰1 小时前
TypeScript 静态类型入门教程:可选静态类型与类型推导详
前端·javascript·typescript
GuWenyue1 小时前
告别命名混乱!5步掌握BEM规范,写出易维护的前端页面
前端·javascript·面试
小林ixn1 小时前
BEM 命名规范与 CSS 重置:打造优雅的按钮页面实战
前端·css