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 應用中實現統一的加載狀態管理和優雅的異步處理體驗。