Vue 项目中如何优雅地管理 Loading 状态
发布于
2024年12月9日
更新于
2025年1月30日
9
分钟阅读
Vue
在前后端通信时,为了提升用户体验,通常会显示一个 loading 状态,以告知用户当前的通信进度。然而,项目中可能有多个地方需要进行 Axios 通信,如果在每一次请求前后都显式地添加 loading 逻辑,代码将变得冗余且难以维护。
为了解决这个问题,我设计了一个通用的 Loading Hook 组件,基于 Element Plus 和 Axios,可以大幅简化代码并提高复用性。以下是详细的实现和使用方法。
实现思路
通过一个 Hook,将 loading 逻辑集中管理,并提供以下功能:
- 控制普通加载状态。
- 支持多个异步请求的统一管理。
- 支持全屏加载效果,适用于需要全局遮罩的场景。
Hook 代码实现
import { ref } from 'vue'
import { ElLoading } from 'element-plus'
type Options = {
/** 初始值 */
initialValue?: boolean
}
export function useLoading({ initialValue = false }: Options = {}) {
/** 是否正在加载 */
const isLoading = ref(initialValue)
/**
* 开始加载
*/
const startLoading = () => {
isLoading.value = true
}
/**
* 结束加载
*/
const stopLoading = () => {
isLoading.value = false
}
/**
* 处理多个异步请求
* @param promises 异步请求列表
* @returns 所有异步请求的结果
*/
const withLoading = async <T>(promises: Array<() => Promise<T>>) => {
startLoading()
try {
return await Promise.all(promises.map((promise) => promise()))
} finally {
stopLoading()
}
}
/**
* 处理多个异步请求,全屏加载
* @param promises 异步请求列表
* @returns 所有异步请求的结果
*/
const withFullscreenLoading = async <T>(promises: Array<() => Promise<T>>) => {
startLoading()
const loading = ElLoading.service({ fullscreen: true })
try {
return await Promise.all(promises.map((promise) => promise()))
} finally {
stopLoading()
loading.close()
}
}
return { isLoading, startLoading, stopLoading, withLoading, withFullscreenLoading }
}
使用方法
以下是一个完整的示例,展示了如何在 Vue 页面中使用 useLoading Hook 来管理加载状态。
<template>
<div class="wrapper">
<button @click="clickHandler">Fetch Japanese Holidays</button>
<hr />
<p>{{ JSON.stringify(holidayList) }}</p>
</div>
</template>
<script setup lang="ts">
import { useLoading } from '@/hooks/use-loading.hook'
import axios from 'axios'
import { ref } from 'vue'
// 使用 useLoading Hook
const { withFullscreenLoading } = useLoading()
const holidayList = ref<any>({})
// 请求逻辑封装
const requestJapaneseHoliday = async () => {
const resp = await axios.get('https://holidays-jp.github.io/api/v1/date.json')
return resp.data
}
// 按钮点击事件
const clickHandler = async () => {
const [data] = await withFullscreenLoading([requestJapaneseHoliday])
holidayList.value = data
}
</script>
优势分析
- 解耦代码逻辑,把 loading 状态的管理提取到 Hook 中,避免每次请求都重复写 start/stop 逻辑,代码更清晰、简洁。
- 支持多请求并发,无论是单个还是多个异步请求,都可以通过
withLoading或withFullscreenLoading轻松管理。 - 全屏加载支持,使用 Element Plus 的 ElLoading,快速实现全局遮罩,提升页面的视觉效果。
- 灵活的复用性,只需一次定义,就可以在整个项目中便捷调用,极大地提升了开发效率。
总结
通过封装useLoading Hook,我们可以优雅地管理 Axios 通信中的加载状态,既简化了代码,又增强了复用性。在实际项目中,这样的通用性设计不仅能减少开发工作量,还能提高代码的可维护性。
希望这个方案对你的项目有所帮助!