Vue Composables 模式

Vue 3 组合式函数(Composables)封装模式,包括通用列表逻辑、加载状态管理等

#tech / dev / frontend #type / concept #status / evergreen

Vue Composables 模式

面向前端开发者的 Vue 3 Composables 封装最佳实践

列表页面通用逻辑

// composables/useTable.ts
export const useTable = <T>(apiFn: (params: any) => Promise<PageResult<T>>) => {
  const loading = ref(false)
  const list = ref<T[]>([])
  const total = ref(0)
  const pageNum = ref(1)
  const pageSize = ref(10)

  // 获取列表
  const getList = async (params = {}) => {
    loading.value = true
    try {
      const res = await apiFn({
        pageNum: pageNum.value,
        pageSize: pageSize.value,
        ...params,
      })
      list.value = res.data.records
      total.value = res.data.total
    } catch (error) {
      console.error('获取列表失败', error)
    } finally {
      loading.value = false
    }
  }

  // 页码改变
  const handlePageChange = (page: number) => {
    pageNum.value = page
    getList()
  }

  // 页大小改变
  const handleSizeChange = (size: number) => {
    pageSize.value = size
    pageNum.value = 1
    getList()
  }

  // 刷新当前页
  const refresh = () => getList()

  // 重置到第一页
  const reset = () => {
    pageNum.value = 1
    getList()
  }

  return {
    loading,
    list,
    total,
    pageNum,
    pageSize,
    getList,
    handlePageChange,
    handleSizeChange,
    refresh,
    reset,
  }
}

// 使用示例
const {
  loading,
  list,
  total,
  getList,
  handlePageChange
} = useTable(getUserListApi)

onMounted(() => getList())

优雅之处

  • 复用了分页、加载、刷新等通用逻辑
  • 类型安全(泛型 <T>
  • 响应式状态自动管理
  • 减少 80% 的模板代码

自动管理 Loading 状态

// composables/useLoading.ts
export const useLoading = () => {
  const loading = ref(false)

  // 自动包装异步函数
  const withLoading = async <T>(fn: () => Promise<T>): Promise<T> => {
    loading.value = true
    try {
      return await fn()
    } finally {
      loading.value = false
    }
  }

  return { loading, withLoading }
}

// 使用示例
const { loading, withLoading } = useLoading()

const handleSubmit = async () => {
  await withLoading(async () => {
    await submitFormApi(formData.value)
    message.success('提交成功')
    await getList()
  })
}

// 模板中
<el-button :loading="loading" @click="handleSubmit">
  提交
</el-button>

全局 Loading

// composables/useGlobalLoading.ts
let loadingInstance: any = null
let requestCount = 0

export const useGlobalLoading = () => {
  const show = () => {
    requestCount++
    if (requestCount === 1) {
      loadingInstance = ElLoading.service({
        lock: true,
        text: '加载中...',
        background: 'rgba(0, 0, 0, 0.7)',
      })
    }
  }

  const hide = () => {
    requestCount = Math.max(0, requestCount - 1)
    if (requestCount === 0) {
      loadingInstance?.close()
      loadingInstance = null
    }
  }

  return { show, hide }
}

优雅之处

  • 自动管理 loading 状态,无需手动 true/false
  • 支持多个请求的 loading 计数
  • 避免 loading 闪烁

创建于 2026/5/27 更新于 2026/5/27