重学 Vu3 之异步组件
基本用法
在大型项目中,一个应用往往需要拆分成多个模块,一般不会同时加载所有的模块。Vue 提供了 defineAsyncComponent 方法,用于异步加载组件,也就是说只有当需要该组件的时候才会从服务器中加载。
defineAsyncComponent 函数可以接收一个返回 promise 组件的函数,import 方法也是返回 promise,所以下面的例子使用了 import 导入组件。
<!-- index.html -->
<div id="app"></div>
<script type="module">
import { createApp, h, defineAsyncComponent } from "https://unpkg.com/vue@3/dist/vue.esm-browser.js";
createApp({
data() {
return {
show: false,
};
},
render() {
return h("div", [
h("button", { onClick: () => (this.show = !this.show) }, "show"),
this.show && h(defineAsyncComponent(() => import("./my-component.js"))),
]);
},
}).mount("#app");
</script>
// my-component.js
export default {
data() {
return {
info: "wow",
};
},
template: `<div>{{ info }}</div>`,
};
从上面的例子可以看出,在根组件创建了一个 show 按钮,点击之后就会使用 defineAsyncComponent 方法从 my-component.js 文件中获取到对应的组件。从控制台可以看出,my-component.js 文件并不是刚开始就从服务器加载出来的,而是当用户点击按钮之后才从服务器获取到该文件。
<!-- index.html -->
<div id="app"></div>
<script type="module">
import { createApp, h, defineAsyncComponent } from "https://unpkg.com/vue@3/dist/vue.esm-browser.js";
import MyComponent from "./my-component.js";
createApp({
data() {
return {
show: false,
};
},
render() {
return h("div", [h("button", { onClick: () => (this.show = !this.show) }, "show"), this.show && h(MyComponent)]);
},
}).mount("#app");
</script>
上面的例子在原来例子的基础上做了修改,不再使用 defineAsyncComponent 函数导入组件,在控制台可以看出 my-component.js 文件一开始就会从服务器中获取。
需要补充说明的是,之前写的文章示例都是使用在线开发环境完成的,这次也尝试使用这种形式,但是出现了报错
Async component loader resolved to undefined. If you are using retry(), make sure to return its return value
,查找相关资料,原来这是一个已知的问题,在 GitHub 中有这个 issue
加载和错误处理
defineAsyncComponent 函数不但可以支持一个函数作为参数,也支持对象作为传参。
function defineAsyncComponent(
source: AsyncComponentLoader | AsyncComponentOptions
): Component
type AsyncComponentLoader = () => Promise<Component>
interface AsyncComponentOptions {
loader: AsyncComponentLoader
loadingComponent?: Component
errorComponent?: Component
delay?: number
timeout?: number
suspensible?: boolean
onError?: (
error: Error,
retry: () => void,
fail: () => void,
attempts: number
) => any
}
loader 属性值是一个返回 promise 组件的函数,delay 属性用于支持延迟加载的毫秒数,loadingComponent 属性用于延迟加载时显示提示组件,timeout 属性可以设置超时的毫秒数,errorComponent 属性用于组件加载出错时显示提示组件。
<!-- index.html -->
<div id="app"></div>
<script type="module">
import { createApp, h, defineAsyncComponent } from "https://unpkg.com/vue@3/dist/vue.esm-browser.js";
createApp({
data() {
return {
show: false,
};
},
render() {
return h("div", [
h("button", { onClick: () => (this.show = !this.show) }, "show"),
this.show &&
h(
defineAsyncComponent({
loader: () =>
new Promise((resolve) => {
setTimeout(() => {
resolve(() => h("div", "asyncComponent"));
}, 3000);
}),
delay: 1000,
loadingComponent: h("div", "loading"),
errorComponent: h("div", "error"),
timeout: 4000,
})
),
]);
},
}).mount("#app");
</script>
在上面的示例中,点击 show 按钮,延迟一秒出现 loadingComponent,3秒后出现 loader 函数对应的组件。
结论
Vue3 通过 defineAsyncComponent 函数来支持异步组件,该函数既支持传入一个返回 promise 组件的函数,也支持传入一个多选项的对象。使用异步组件后可以实现按需从服务器获取对应组件,提高性能。
参考资料
转载自:https://juejin.cn/post/7222529227677270072