学习Vue3 defineAsyncComponent Api
使用 Vue3 的 DefileAsyncComponent
功能可让我们懒加载组件,说白了就是创建一个只有在需要时才会加载的异步组件。
这是改进初始页面加载的好方法,因为我们的应用程序将加载到较小的块中而不是必须在页面加载时加载每个组件。
在本文中,我们将学习有关defineAsyncComponent
的所有知识,并学习一个懒加载弹出窗口的例子。
defineAsyncComponent 是什么?
const AsyncComp = defineAsyncComponent( () => new Promise((resolve, reject) => { resolve({ template: '<div>I am async!</div>' }) }) )
defineAsyncComponent
可以接受一个返回 Promise
的工厂函数。Promise 的 resolve
回调应该在服务端返回组件定义后被调用。你也可以调用 reject(reason)
来表示加载失败。
defineAsyncComponent
可以从 vue 中导入,并使用:
import { defineAsyncComponent } from "vue" // simple usage const LoginPopup = defineAsyncComponent(() => import("./components/LoginPopup.vue"))
这是defineAsyncComponent
的最简单方法,对于高阶用法,defineAsyncComponent
可以接受一个对象:
const AsyncPopup = defineAsyncComponent({ loader: () => import("./LoginPopup.vue"), // 加载异步组件时要使用的组件 loadingComponent: LoadingComponent, // 加载失败时要使用的组件 errorComponent: ErrorComponent, // 在显示 loadingComponent 之前的延迟 | 默认值:200(单位 ms) delay: 1000, // 如果提供了 timeout ,并且加载组件的时间超过了设定值,将显示错误组件 // 默认值:Infinity(即永不超时,单位 ms) timeout: 3000 })
基础已经介绍完了,接着,我们来做个例子。
使用 defineAsyncComponent 异步加载 Popup 组件
在这个例子中,我们将使用一个由点击按钮触发的登录弹框。
我们不需要我们的应用程序在每次加载时都加载这个组件,因为只有在用户执行特定的动作时才需要它。
下面是 login 组件的实现:
// LoginPopup.vue <template> <div class="popup"> <div class="content"> <h4> Login to your account </h4> <input type="text" placeholder="Email" /> <input type="password" placeholder="Password" /> <button> Log in </button> </div> </div> </template> <script> </script> <style scoped> .popup { position: fixed; width: 100%; top: ; left: ; height: 100%; background-color: rgba(, , , 0.2); display: flex; justify-content: center; align-items: center; } .content { min-width: 200px; width: 30%; background: #fff; height: 200px; padding: 10px; border-radius: 5px; } input[type="text"], input[type="password"] { border: ; outline: ; border-bottom: 1px solid #eee; width: 80%; margin: auto; font-size: 0.5em; } button { border: ; margin-top: 50px; background-color:#8e44ad; color: #fff; padding: 5px 10px; font-size: 0.5em; } </style>
效果如下:
在其它组件中导入它:
<template> <button @click="show = true"> Login </button> <login-popup v-if="show" /> </template> <script> import LoginPopup from './components/LoginPopup.vue' export default { components: { LoginPopup }, data() { return { show: false } } } </script>
我们可以使用 defineAsyncComponent
,只在需要的时候加载它(按钮被点击时使用v-if
来切换)。
<!-- Use defineAsyncComponent --> <template> <button @click="show = true"> Login </button> <login-popup v-if="show" /> </template> <script> import { defineAsyncComponent } from 'vue' export default { components: { "LoginPopup" : defineAsyncComponent(() => import('./components/LoginPopup.vue')) }, data() { return { show: false } } } </script>
这个用法看起来和上面的差不多,不急,我们 F12
打开控制台。
如果我们不使用defineAsyncComponent
,一旦我们的页面加载,我们就会看到我们的应用程序从服务器上获得LoginPopup.vue
。虽然在这个例子中,性能问题不那么严重,但如果我们有几十个组件这样做,性能上多多少少还是有影响的。
然而,如果我们使用defineAsyncComponent
查看同一个标签,会注意到,当我们的页面加载时,LoginPopup.vue
是没有的,这是因为它还没有被加载。
但,如果切换按钮,我们就可以看到它了:
这有助于我们实现最佳性能。我们只想在我们的页面初始加载时加载需要的组件。有条件渲染的组件在我们的页面加载时往往是不需要的,所以为什么要让我们的应用程序加载它们呢?
如何与异步的 setup 方法一起使用?
不管我们是否用defineAsyncComponent
来异步加载,任何具有异步 setup
方法的组件都必须用<Suspense>
来包装。
简而言之,创建一个异步 setup
函数是我们的一种选择,可以让我们的组件在渲染前等待一些 API 调用或其他异步操作。
下面是带有异步setup
的组件,使用setTimeout()
模拟 API 调用
<template> <div class="popup"> <div class="content"> <p> Loaded API: {{ article }} </p> <h4> Login to your account </h4> <input type="text" placeholder="Email" /> <input type="password" placeholder="Password" /> <button> Log in </button> </div> </div> </template> <script> const getArticleInfo = async () => { // wait 3 seconds to mimic API call await new Promise(resolve => setTimeout(resolve, 1000)); const article = { title: 'My Vue 3 Article', author: 'Matt Maribojoc' } return article } export default { async setup() { const article = await getArticleInfo() console.log(article) return { article } } } </script>
我们可以使用或不使用defineAsyncComponent
将它导入到组件中:
import LoginPopup from './components/LoginPopup.vue' // OR const LoginPopup = defineAsyncComponent(() => import("./components/LoginPopup.vue"))
但如果我们想让它在我们的模板中渲染,我们需要把它包在一个Suspense
元素中。这将等待我们的setup
解析后,然后再尝试渲染我们的组件。
Suspense
的一个很好的特点是,我们可以使用槽和模板显示回退内容。回退内容将显示,直到setup
函数解析,我们的组件准备好渲染。 请注意,v-if
已经从组件本身移到了我们的 Suspense 组件上,所以所有回退内容都会显示。
<template> <button @click="show = true"> Login </button> <Suspense v-if="show"> <template #default> <login-popup /> </template> <template #fallback> <p> Loading... </p> </template> </Suspense> </template>
下面是运行结果,会看到 "Loading…"
,然后在3
秒后(setTimeout
的硬编码值)组件渲染。
默认情况下,我们使用defineAsyncComponent
定义的所有组件都是可Suspense
的。
这意味着如果一个组件的父链中有 Suspense,它将被视为该 Suspense 的一个异步依赖。我们的组件的加载、错误、延迟和超时选项将被忽略,而是由 Suspense 来处理。
总结
当构建包许多组件的大型项目时,defineAsyncComponent
是非常有用的。当我们使用懒加载组件时,可以更快地加载页面,改善用户体验,最终提高应用的留存率和转换率。
码云笔记 » 学习Vue3 defineAsyncComponent Api