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 闪烁