学习Vue3 defineAsyncComponent Api

目录
文章目录隐藏
  1. defineAsyncComponent 是什么?
  2. 使用 defineAsyncComponent 异步加载 Popup 组件
  3. 如何与异步的 setup 方法一起使用?
  4. 总结

使用 Vue3 的 DefileAsyncComponent功能可让我们懒加载组件,说白了就是创建一个只有在需要时才会加载的异步组件。

这是改进初始页面加载的好方法,因为我们的应用程序将加载到较小的块中而不是必须在页面加载时加载每个组件。

学习 Vue defineAsyncComponent Api

在本文中,我们将学习有关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>

效果如下:

使用 defineAsyncComponent 异步加载 Popup 组件

在其它组件中导入它:

<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。虽然在这个例子中,性能问题不那么严重,但如果我们有几十个组件这样做,性能上多多少少还是有影响的。

学习 Vue3 defineAsyncComponent Api

然而,如果我们使用defineAsyncComponent查看同一个标签,会注意到,当我们的页面加载时,LoginPopup.vue是没有的,这是因为它还没有被加载。

学习 Vue3 defineAsyncComponent Api

但,如果切换按钮,我们就可以看到它了:

学习 Vue3 defineAsyncComponent Api

这有助于我们实现最佳性能。我们只想在我们的页面初始加载时加载需要的组件。有条件渲染的组件在我们的页面加载时往往是不需要的,所以为什么要让我们的应用程序加载它们呢?

如何与异步的 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是非常有用的。当我们使用懒加载组件时,可以更快地加载页面,改善用户体验,最终提高应用的留存率和转换率。

「点点赞赏,手留余香」

1

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » 学习Vue3 defineAsyncComponent Api

发表回复