×

Vue 全局 Loading 最佳写法!官方推荐!

独孤求败 独孤求败 发表于2026-04-24 09:18:29 浏览40 评论0

抢沙发发表评论

大家做Vue项目,肯定都碰到过loading状态管理这个头疼事。

一个页面要调三个接口,你是怎么写loading的?难道是这样?

const loading1 = ref(false)
const loading2 = ref(false)
const loading3 = ref(false)

// 然后三个地方分别控制

太土了。要么全屏loading闪来闪去,要么页面上一堆loading状态各管各的,巨丑。

今天分享一个我们项目里正在用的方案,用了Pinia,也就一百行代码,体验直接起飞。

核心思路:让组件自己上报,让store统一调度。

想象一下:每个组件只管自己的loading状态,告诉全局store“我在加载”。store负责监听所有组件的状态,只要还有一个组件在加载,就保持全屏loading。

这样做的好处特别明显:

  • 组件逻辑干净,不用关心别人是不是也在加载

  • 多个请求自动合并成一个loading展示

  • 组件卸载自动清理,不怕内存泄漏

上代码,看看具体怎么实现。

先看store部分,核心其实就几十行:

// loading-store.js
exportconst useLoadingStore = defineStore('loading', () => {
    // 存所有组件的loading状态
    const loadingSources = ref([])
    
    // 组件用这个注册自己
    const addLoadingSource = (source) => {
        loadingSources.value.push(source)
    }
    
    // 组件卸载时移除
    const removeLoadingSource = (source) => {
        const index = loadingSources.value.indexOf(source)
        if (index > -1) {
            loadingSources.value.splice(index, 1)
        }
    }
    
    // 关键:只要有一个组件在loading,就返回true
    const isLoading = computed(() =>
        loadingSources.value.some(source => toValue(source))
    )
    
    // 监听变化,自动显示/隐藏
    watch(isLoading, (loading) => {
        if (loading) {
            // 显示Element Plus的全屏loading
            ElLoading.service({ fullscreentrue })
        } else {
            // 所有加载都完成了,关闭
            // 这里需要稍微处理下实例引用,简单起见先这么写
        }
    })
    
    return { addLoadingSource, removeLoadingSource }
})

再看组件里怎么用,简单得离谱:

<script setup>
import { ref } from 'vue'
import { useLoadingStore } from './loading-store'

const loadingStore = useLoadingStore()
const myLoading = ref(false) // 这是我自己的loading状态

// 注册一下,告诉store“我的状态你帮忙盯着”
loadingStore.addLoadingSource(myLoading)

const fetchData = async () => {
    myLoading.value = true // 就改自己的状态就行
    try {
        await api.getData()
    } finally {
        myLoading.value = false // 完成就关
    }
}

// 组件卸载时记得清理(重要!)
onBeforeUnmount(() => {
    loadingStore.removeLoadingSource(myLoading)
})
</script>

看到没?组件完全不用管全局的loading怎么显示隐藏,只管自己的myLoading.value = true/false就行。其他的,store全帮你搞定。

这方案妙在哪?

自动合并请求:比如页面同时发三个请求,三个组件都把loading设为true,但全屏loading只出现一次。最后一个请求结束,loading才消失。

组件卸载自动清理:有些同学可能担心,组件都销毁了,它的loading状态还留在store里怎么办?所以我们一定要在onBeforeUnmount里移除注册。这是好习惯。

支持各种loading形式:我这里用了toValue,是VueUse里的工具函数,它能处理ref、computed、普通值、getter函数...挺方便的。所以你的loading状态可以这样:

// 都可以
const loading = ref(false)
const loading = computed(() => someCondition)
const loading = () => isLoading.value

可扩展性强:如果想加个最小显示时间(防止loading一闪而过),或者想区分“页面loading”和“局部loading”,在store里加逻辑就行,组件完全不用改。


群贤毕至

访客