在 Vue 3 中全局使用 Suspense 组件

发布于:2025-07-05 ⋅ 阅读:(17) ⋅ 点赞:(0)

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 = true
      this.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>

注意事项

  1. 错误处理:Suspense 本身不处理错误,需要使用 onErrorCaptured 或 errorCaptured 钩子

  2. 嵌套 Suspense:可以嵌套使用 Suspense,内层 Suspense 会优先于外层

  3. SSR 兼容:在服务端渲染时 Suspense 行为有所不同

  4. 组合式 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 应用中实现统一的加载状态管理和优雅的异步处理体验。


网站公告

今日签到

点亮在社区的每一天
去签到