- Published on
Vue - 异步组件
- Authors
- Name
- Deng Hua
异步组件是 Vue.js 中以异步方式加载的特殊组件,它们仅在需要时从服务器获取,并不包含在初始页面加载中。这种方法可以通过减少不必要的网络请求来降低网络开销,缩短页面加载时间,从而增强用户体验。
目录
哪些组件适合异步加载?
大型或复杂的组件,例如页面底部的slider,不是第一时间要渲染的UI等。
基于用户交互(例如弹窗和Modal窗口)呈现的组件。
用于访问频率较低或用户较少的功能的组件。
Vue.js 异步组件的实际使用
创建一个简单的删除确认Modal
<!-- AppModal.vue -->
<template>
<div class="backdrop">
<div class="modal">
<div v-if="slots.header" class="header">
<slot name="header" />
</div>
<div v-if="slots.body" class="body">
<slot name="body" />
</div>
<div v-if="slots.footer" class="footer">
<slot name="footer" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useSlots } from "vue";
const slots = useSlots();
</script>
<style scoped>
.backdrop {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.03);
z-index: 10;
}
.modal {
width: 100%;
width: 320px;
background: #fff;
border: 1px solid #e6e6e6;
border-radius: 16px;
}
.header {
width: 100%;
padding: 16px 24px;
border-bottom: 1px solid #e6e6e6;
background: #fafafa;
border-top-left-radius: 16px;
border-top-right-radius: 16px;
}
.body {
width: 100%;
padding: 16px 24px;
}
.footer {
width: 100%;
padding: 16px 24px;
}
</style>
删除确认Modal:
<!-- DeleteConfirmationModal.vue -->
<template>
<AppModal>
<template #header>
<p class="heading">删除确认</p>
</template>
<template #body>
您确定要删除此内容吗?这将无法撤销。
</template>
<template #footer>
<div class="controls">
<button @click="handleCancel" class="cancel">取消</button>
<button @click="handleDelete" class="delete">删除</button>
</div>
</template>
</AppModal>
</template>
<script setup lang="ts">
import AppModal from "./AppModal.vue";
const emit = defineEmits<{
cancel: [];
delete: [];
}>();
function handleCancel() {
emit("cancel");
}
function handleDelete() {
emit("delete");
}
</script>
<style scoped>
.heading {
font-weight: 600;
}
.controls {
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
}
.cancel,
.delete {
border: none;
background: none;
cursor: pointer;
padding: 12px 24px;
border-radius: 12px;
font-weight: 700;
}
.delete {
background: red;
color: #fff;
}
</style>
最后在App.vue内使用
<template>
<DeleteConfirmationModal v-if="deleteModalOpen" @cancel="handleCancel" @delete="handleDeleteConfirmation" />
<div class="resources">
<div v-if="resourceExists" class="resource">
<p>一段内容</p>
<button class="delete" @click="handleDelete">删除</button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import DeleteConfirmationModal from "./DeleteConfirmationModal.vue";
const deleteModalOpen = ref(false);
const resourceExists = ref(true);
function handleDelete() {
deleteModalOpen.value = true;
}
function handleCancel() {
deleteModalOpen.value = false;
}
function handleDeleteConfirmation() {
resourceExists.value = false;
deleteModalOpen.value = false;
}
</script>
<style scoped>
.delete {
border: none;
background: none;
cursor: pointer;
background: red;
color: #fff;
padding: 8px 12px;
border-radius: 10px;
font-weight: 700;
}
.resources {
width: 100%;
height: 100dvh;
display: flex;
justify-content: center;
align-items: center;
}
.resource {
display: flex;
gap: 16px;
align-items: center;
font-weight: 500;
}
</style>
最终效果:
我们跳转到 DevTools 中的 network 选项卡,可以注意到我们的Modal(<AppModal>
和<DeleteConfirmationModal>
)是在应用初次加载时下载的,即便它并不需要首次加载。
当代码和应用功能变得庞大且复杂时,这可能会导致用户等待更长时间才能看到所需的内容。
异步组件可以快捷的解决这个问题。通过 DefineAsyncComponent
函数来利用它们,Vue为我们提供了开箱即用的功能:
import { defineAsyncComponent } from "vue";
const DeleteConfirmationModal = defineAsyncComponent(
() => import("./DeleteConfirmationModal.vue")
);
DefineAsyncComponent
函数接受一个返回 Promise
的loader函数,这是 ES Module动态导入的模块。我们可以利用它在我们的应用中实现异步加载:
在导入DeleteConfirmationModal
组件的地方改写逻辑:
// import DeleteConfirmationModal from "./DeleteConfirmationModal.vue";
import { ref, defineAsyncComponent, Component } from "vue";
const DeleteConfirmationModal = defineAsyncComponent(
(): Promise<Component> => import('./DeleteConfirmationModal.vue')
)
// ...
更新上述代码后,我们可以在 DevTools 中注意到,在初始页面加载期间不再下载Modal,Modal组件以及所有的依赖项会在用户单击“删除”按钮后下载。
这种方法可以实现更快的初始页面加载速度,从而提高应用程序的性能,特别是首屏性能,并且还可以节省不必要的网络请求。
以这个例子为例,实际业务中,可能一定比例的用户永远都不会用到删除功能。
End.