Skip to content

Composables 总览

Composables 是 Vue 3 组合式 API 的核心概念,用于封装和复用有状态的逻辑。

什么是 Composables?

Composables 是利用 Vue 3 组合式 API 来封装和复用有状态逻辑的函数。

特点

  • use 开头命名
  • 返回响应式的状态和方法
  • 可以在组件的 setup() 中使用
  • 支持组合和嵌套使用

Composables 分类

AI 相关

Composable说明文档
useAiActionAI 操作助手查看

表格相关

Composable说明文档
useTableSelection表格选择管理查看

实时通信相关

Composable说明文档
useStompSTOMP 协议 WebSocket查看
useDictSync字典数据同步查看
useOnlineCount在线人数统计查看

布局相关

布局相关的 Composables 位于 src/layouts/useLayout.ts

Composable说明
useLayout布局管理(侧边栏、设备检测等)

使用方式

基本用法

vue
<script setup lang="ts">
import { useStomp, useDictSync, useOnlineCount } from '@/composables'

// WebSocket 连接
const { connect, disconnect } = useStomp()

// 字典同步
const { startSync, stopSync } = useDictSync()

// 在线人数
const { onlineCount } = useOnlineCount()

onMounted(() => {
  connect()
  startSync()
})

onUnmounted(() => {
  disconnect()
  stopSync()
})
</script>

组合使用

vue
<script setup lang="ts">
import { useTableSelection } from '@/composables'

const { 
  selectedIds, 
  selectedRows, 
  handleSelectionChange,
  clearSelection 
} = useTableSelection()

// 表格选择变化时
const onSelectionChange = (rows: any[]) => {
  handleSelectionChange(rows)
}

// 批量删除
const handleBatchDelete = () => {
  if (selectedIds.value.length === 0) {
    ElMessage.warning('请选择要删除的数据')
    return
  }
  // 执行删除...
}
</script>

创建自定义 Composable

基本结构

typescript
// composables/useCounter.ts
import { ref, computed } from 'vue'

export function useCounter(initialValue = 0) {
  // 响应式状态
  const count = ref(initialValue)
  
  // 计算属性
  const double = computed(() => count.value * 2)

  // 方法
  function increment() {
    count.value++
  }

  function decrement() {
    count.value--
  }

  // 返回状态和方法
  return {
    count,
    double,
    increment,
    decrement
  }
}

带副作用的 Composable

typescript
// composables/useEventListener.ts
import { onMounted, onUnmounted } from 'vue'

export function useEventListener(
  target: EventTarget,
  event: string,
  callback: EventListener
) {
  onMounted(() => {
    target.addEventListener(event, callback)
  })
  
  onUnmounted(() => {
    target.removeEventListener(event, callback)
  })
}

异步 Composable

typescript
// composables/useFetch.ts
import { ref } from 'vue'

export function useFetch<T>(url: string) {
  const data = ref<T | null>(null)
  const error = ref<Error | null>(null)
  const loading = ref(false)

  async function fetch() {
    loading.value = true
    error.value = null
    
    try {
      const response = await axios.get(url)
      data.value = response.data
    } catch (e) {
      error.value = e as Error
    } finally {
      loading.value = false
    }
  }

  return {
    data,
    error,
    loading,
    fetch
  }
}

项目 Composables 导出

项目通过 src/composables/index.ts 统一导出所有 Composables:

typescript
// WebSocket 服务
export { setupWebSocket, cleanupWebSocket } from "./websocket";
export { useStomp, useDictSync, useOnlineCount } from "./websocket";
export type { DictMessage, DictChangeMessage, DictChangeCallback } from "./websocket";

// AI 相关
export { useAiAction } from "./ai/useAiAction";
export type { UseAiActionOptions, AiActionHandler } from "./ai/useAiAction";

// 表格相关
export { useTableSelection } from "./table/useTableSelection";

最佳实践

1. 命名规范

  • 使用 use 前缀
  • 使用驼峰命名
  • 名称清晰表达功能
typescript
// ✅ 好的命名
useTableSelection
useDictSync
useOnlineCount

// ❌ 不好的命名
tableSelection
dictSync
getOnlineCount

2. 单一职责

每个 Composable 只负责一个功能:

typescript
// ✅ 好 - 单一职责
function useTableSelection() { /* 只处理表格选择 */ }
function useTablePagination() { /* 只处理分页 */ }

// ❌ 不好 - 职责过多
function useTable() { /* 选择、分页、排序、筛选... */ }

3. 类型定义

提供完整的 TypeScript 类型:

typescript
interface UseCounterOptions {
  min?: number
  max?: number
}

interface UseCounterReturn {
  count: Ref<number>
  increment: () => void
  decrement: () => void
}

export function useCounter(
  initialValue = 0,
  options?: UseCounterOptions
): UseCounterReturn {
  // ...
}

4. 副作用清理

确保清理事件监听等副作用:

typescript
export function useEventListener(target, event, callback) {
  onMounted(() => {
    target.addEventListener(event, callback)
  })
  
  // 清理副作用
  onUnmounted(() => {
    target.removeEventListener(event, callback)
  })
}

5. 参数灵活性

支持多种参数形式:

typescript
// 支持 ref 和普通值
export function useTitle(title: MaybeRef<string>) {
  const titleRef = ref(title)
  
  watch(titleRef, (newTitle) => {
    document.title = newTitle
  }, { immediate: true })
  
  return titleRef
}

// 使用
useTitle('页面标题')
useTitle(ref('响应式标题'))

相关文档

基于 MIT 许可发布