跳轉到內容

非同步元件

基本用法

在大型應用中,我們可能需要將應用分割成更小的塊,並且只在需要時從伺服器載入元件。為此,Vue提供了一個 defineAsyncComponent 函式

js
import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() => {
  return new Promise((resolve, reject) => {
    // ...load component from server
    resolve(/* loaded component */)
  })
})
// ... use `AsyncComp` like a normal component

如你所見,defineAsyncComponent 接受一個返回Promise的載入函式。當從伺服器檢索到元件定義時,應呼叫Promise的resolve回撥。你也可以呼叫 reject(reason) 來指示載入失敗。

ES模組動態匯入 也返回一個Promise,所以我們通常將它與 defineAsyncComponent 結合使用。Vite和webpack等打包器也支援這種語法(並將用作包分割點),因此我們可以用它來匯入Vue SFC

js
import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() =>
  import('./components/MyComponent.vue')
)

生成的 AsyncComp 是一個包裝元件,它僅在頁面實際渲染時呼叫載入函式。此外,它還會將任何props和slots傳遞給內部元件,因此你可以使用非同步包裝器無縫替換原始元件,同時實現懶載入。

與普通元件一樣,非同步元件可以透過 app.component() 使用 全域性註冊

js
app.component('MyComponent', defineAsyncComponent(() =>
  import('./components/MyComponent.vue')
))

本地註冊元件 時也可以使用 defineAsyncComponent

vue
<script>
import { defineAsyncComponent } from 'vue'

export default {
  components: {
    AdminPage: defineAsyncComponent(() =>
      import('./components/AdminPageComponent.vue')
    )
  }
}
</script>

<template>
  <AdminPage />
</template>

它們也可以直接在其父元件內部定義

vue
<script setup>
import { defineAsyncComponent } from 'vue'

const AdminPage = defineAsyncComponent(() =>
  import('./components/AdminPageComponent.vue')
)
</script>

<template>
  <AdminPage />
</template>

載入和錯誤狀態

非同步操作不可避免地涉及載入和錯誤狀態 - defineAsyncComponent() 透過高階選項支援處理這些狀態

js
const AsyncComp = defineAsyncComponent({
  // the loader function
  loader: () => import('./Foo.vue'),

  // A component to use while the async component is loading
  loadingComponent: LoadingComponent,
  // Delay before showing the loading component. Default: 200ms.
  delay: 200,

  // A component to use if the load fails
  errorComponent: ErrorComponent,
  // The error component will be displayed if a timeout is
  // provided and exceeded. Default: Infinity.
  timeout: 3000
})

如果提供了載入元件,它將在內部元件載入時首先顯示。在載入元件顯示之前有一個預設的200ms延遲 - 這是因為在快速網路上,載入狀態可能替換得太快,最終看起來像閃爍。

如果提供了錯誤元件,當載入函式返回的Promise被拒絕時,它將顯示。你也可以指定一個超時時間,當請求耗時過長時顯示錯誤元件。

延遲水合

本節僅適用於使用 伺服器端渲染 的情況。

在Vue 3.5+中,非同步元件可以透過提供水合策略來控制它們何時水合。

  • Vue提供了一些內建的水合策略。這些內建策略需要單獨匯入,以便在不使用時進行搖樹最佳化。

  • 設計故意保持低階以增加靈活性。未來可以在核心或高階解決方案(例如 Nuxt)之上構建編譯器語法糖。

空閒時啟用

透過 requestIdleCallback 啟用。

js
import { defineAsyncComponent, hydrateOnIdle } from 'vue'

const AsyncComp = defineAsyncComponent({
  loader: () => import('./Comp.vue'),
  hydrate: hydrateOnIdle(/* optionally pass a max timeout */)
})

可見時啟用

透過 IntersectionObserver 使元素可見時啟用。

js
import { defineAsyncComponent, hydrateOnVisible } from 'vue'

const AsyncComp = defineAsyncComponent({
  loader: () => import('./Comp.vue'),
  hydrate: hydrateOnVisible()
})

可以可選地傳遞一個選項物件給觀察者。

js
hydrateOnVisible({ rootMargin: '100px' })

媒體查詢時啟用

當指定的媒體查詢匹配時啟用。

js
import { defineAsyncComponent, hydrateOnMediaQuery } from 'vue'

const AsyncComp = defineAsyncComponent({
  loader: () => import('./Comp.vue'),
  hydrate: hydrateOnMediaQuery('(max-width:500px)')
})

互動時啟用

當在元件元素上觸發指定的事件時啟用。啟用的 hydration 事件將在 hydration 完成後重放。

js
import { defineAsyncComponent, hydrateOnInteraction } from 'vue'

const AsyncComp = defineAsyncComponent({
  loader: () => import('./Comp.vue'),
  hydrate: hydrateOnInteraction('click')
})

也可以是多個事件型別的列表。

js
hydrateOnInteraction(['wheel', 'mouseover'])

自定義策略

ts
import { defineAsyncComponent, type HydrationStrategy } from 'vue'

const myStrategy: HydrationStrategy = (hydrate, forEachElement) => {
  // forEachElement is a helper to iterate through all the root elements
  // in the component's non-hydrated DOM, since the root can be a fragment
  // instead of a single element
  forEachElement(el => {
    // ...
  })
  // call `hydrate` when ready
  hydrate()
  return () => {
    // return a teardown function if needed
  }
}

const AsyncComp = defineAsyncComponent({
  loader: () => import('./Comp.vue'),
  hydrate: myStrategy
})

與 Suspense 一起使用

非同步元件可以與內建的 <Suspense> 元件一起使用。有關 <Suspense> 和非同步元件之間互動的文件,請參閱 專門的章節

非同步元件已載入