在 Vue 3 中全局使用 Suspense 组件
Suspense 是 Vue 3 引入的一个内置组件,不需要引用可以直接用。用于处理异步依赖的等待状态。虽然 Suspense 主要用于异步组件,但你也可以全局地使用它来管理整个应用的加载状态。
全局 Suspense 的基本用法
1. 在根组件中使用 Suspense
// main.js 或 main.ts
import { createApp } from 'vue'
import App from './App.vue'createApp(App).mount('#app')
<!-- App.vue -->
<template><Suspense><router-view /><template #fallback><div class="loading-indicator">加载中...</div></template></Suspense>
</template><script>
export default {name: 'App'
}
</script><style>
.loading-indicator {display: flex;justify-content: center;align-items: center;height: 100vh;font-size: 1.5rem;
}
</style>
2. 结合异步组件使用
// 路由配置示例 (router.js)
import { createRouter, createWebHistory } from 'vue-router'const Home = () => ({component: import('./views/Home.vue'),loading: LoadingComponent, // 可选error: ErrorComponent, // 可选delay: 200, // 延迟显示加载组件timeout: 3000 // 超时时间
})const routes = [{ path: '/', component: Home }
]const router = createRouter({history: createWebHistory(),routes
})export default router
高级全局 Suspense 实现
1. 创建全局加载状态管理
javascript
// stores/loading.js (使用Pinia)
import { defineStore } from 'pinia'export const useLoadingStore = defineStore('loading', {state: () => ({isLoading: false,message: '加载中...'}),actions: {startLoading(message) {this.isLoading = truethis.message = message || '加载中...'},stopLoading() {this.isLoading = false}}
})
2. 创建全局 Suspense 组件
vue
<!-- components/GlobalSuspense.vue -->
<template><Suspense @pending="onPending" @resolve="onResolve" @fallback="onFallback"><slot /><template #fallback><div v-if="isLoading" class="global-loading"><div class="spinner"></div><p>{{ message }}</p></div></template></Suspense>
</template><script setup>
import { useLoadingStore } from '@/stores/loading'const loadingStore = useLoadingStore()
const { isLoading, message } = storeToRefs(loadingStore)const onPending = () => {loadingStore.startLoading()
}const onResolve = () => {loadingStore.stopLoading()
}const onFallback = () => {// 可以添加额外的回调逻辑
}
</script><style>
.global-loading {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background: rgba(255, 255, 255, 0.8);display: flex;flex-direction: column;justify-content: center;align-items: center;z-index: 9999;
}.spinner {border: 4px solid #f3f3f3;border-top: 4px solid #3498db;border-radius: 50%;width: 40px;height: 40px;animation: spin 1s linear infinite;
}@keyframes spin {0% { transform: rotate(0deg); }100% { transform: rotate(360deg); }
}
</style>
3. 在应用中使用全局 Suspense
vue
<!-- App.vue -->
<template><GlobalSuspense><router-view /></GlobalSuspense>
</template><script setup>
import GlobalSuspense from '@/components/GlobalSuspense.vue'
</script>
注意事项
-
错误处理:Suspense 本身不处理错误,需要使用
onErrorCaptured
或errorCaptured
钩子 -
嵌套 Suspense:可以嵌套使用 Suspense,内层 Suspense 会优先于外层
-
SSR 兼容:在服务端渲染时 Suspense 行为有所不同
-
组合式 API:在 setup 中使用 async 时,组件会自动成为 Suspense 的异步依赖
错误处理示例
vue
<template><Suspense><template #default><AsyncComponent /></template><template #fallback><div>Loading...</div></template></Suspense>
</template><script setup>
import { onErrorCaptured } from 'vue'
import AsyncComponent from './AsyncComponent.vue'onErrorCaptured((error) => {console.error('Error caught by Suspense:', error)// 可以在这里显示错误界面return false // 阻止错误继续向上传播
})
</script>
通过这种方式,你可以在整个 Vue 3 应用中实现统一的加载状态管理和优雅的异步处理体验。