外觀
非同步元件
基本用法
在大型應用中,我們可能需要將應用分割成更小的塊,並且只在需要時從伺服器載入元件。為此,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')
))
它們也可以直接在其父元件內部定義
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>
和非同步元件之間互動的文件,請參閱 專門的章節。