5分钟了解Vue3 defineAsyncComponent - Vue3 的异步挂载

5分钟了解Vue3 defineAsyncComponent - Vue3 的异步挂载
5分钟了解 Vue 3defineAsyncComponentVue 3 的异步挂载在 Vue 项目中并不是所有组件都需要在页面打开时立刻加载。比如一个只有点击按钮后才出现的登录弹窗、一张位于页面底部的复杂图表或者仅管理员能够访问的操作面板。如果这些组件都跟随首屏代码一起下载会让初次加载变得更慢。defineAsyncComponent就是用来解决这个问题的等组件真正需要显示时再去加载它。严格来说“异步挂载”是一种便于理解的说法。Vue 并没有把组件的挂载流程变成异步而是先异步加载组件代码加载完成后再按照正常流程挂载组件。一、先看最简单的写法假设项目中有一个体积较大的图表组件scriptsetupimport{defineAsyncComponent}fromvueconstUserChartdefineAsyncComponent(()import(./components/UserChart.vue))/scripttemplateUserChart//template这段代码做了两件事import(./components/UserChart.vue)返回一个 Promise用来异步加载组件。defineAsyncComponent把这个加载过程包装成一个可以直接使用的 Vue 组件。因此UserChart在模板中的用法和普通组件没有区别。传递props、监听事件和使用插槽也都照常进行UserChart :user-iduserId loadedhandleLoaded template #empty暂无数据/template /UserChart二、它到底什么时候开始加载异步组件的加载器会在组件真正被渲染时执行。例如下面的UserChart只有在showChart变成true后才会开始加载scriptsetupimport{ref,defineAsyncComponent}fromvueconstshowChartref(false)constUserChartdefineAsyncComponent(()import(./components/UserChart.vue))/scripttemplatebuttonclickshowChart true查看图表/buttonUserChartv-ifshowChart//template可以把整个过程理解为用户点击按钮 → showChart 变为 true → Vue 开始下载 UserChart 的代码 → 下载完成 → 创建并挂载 UserChart配合 Vite、webpack 等构建工具时动态import()通常会把组件拆成独立的代码文件。这样用户没有打开图表就不必下载图表组件的代码。三、给加载过程加上反馈网络请求需要时间也可能失败。实际项目中建议使用配置对象为异步组件补充加载、失败和超时状态script setupimport{defineAsyncComponent}fromvueimportLoadingViewfrom./components/LoadingView.vueimportErrorViewfrom./components/ErrorView.vueconstUserChartdefineAsyncComponent({loader:()import(./components/UserChart.vue),// 加载期间显示的组件loadingComponent:LoadingView,// 延迟 200ms 再显示加载状态避免内容一闪而过delay:200,// 加载失败时显示的组件errorComponent:ErrorView,// 超过 10 秒仍未完成就按加载失败处理timeout:10_000})/scripttemplateUserChart//template常用配置可以简单记成下面这张表配置作用loader返回 Promise 的组件加载函数loadingComponent加载过程中显示的占位组件delay延迟多久显示加载组件默认是 200mserrorComponent加载失败时显示的组件timeout加载超过指定毫秒数后按失败处理onError自定义失败处理例如重试四、加载失败时自动重试在移动网络下组件可能因为短暂断网而加载失败。可以通过onError决定重试还是结束constUserChartdefineAsyncComponent({loader:()import(./components/UserChart.vue),onError(error,retry,fail,attempts){if(attempts3){retry()}else{fail()}}})这里的逻辑是前三次失败时继续尝试超过三次后停止加载。实际项目中还可以结合错误类型只对网络问题进行重试避免无意义地重复请求。五、它和路由懒加载有什么区别两者都使用动态import()目的也都是按需加载代码但使用位置不同。路由懒加载通常直接写在路由配置中constroutes[{path:/report,component:()import(./views/ReportView.vue)}]而defineAsyncComponent更适合页面内部的普通组件constHeavyChartdefineAsyncComponent(()import(./components/HeavyChart.vue))可以这样记页面级组件优先考虑路由懒加载。页面内部的大组件、弹窗或低频功能考虑defineAsyncComponent。在 Vue Router 的路由配置中通常不需要再额外套一层defineAsyncComponent。六、什么时候适合使用defineAsyncComponent比较适合这些场景体积较大的图表、编辑器、地图等组件用户操作后才出现的弹窗或抽屉页面下方、首屏暂时看不到的复杂模块只有少数用户会使用的功能需要按条件展示的管理后台模块。不过也不是所有组件都值得异步加载。按钮、标题、导航栏这类体积很小且首屏必须显示的组件如果也拆成异步组件反而会增加额外请求和状态处理让代码变得更复杂。七、最后总结defineAsyncComponent的核心并不复杂constAsyncComponentdefineAsyncComponent(()import(./AsyncComponent.vue))它带来的主要价值有三个组件用到时再加载减少首屏需要下载的代码。异步组件的使用方式与普通组件基本一致。可以处理加载中、加载失败、超时和重试等状态。所以下次遇到“这个组件很大但用户不一定会打开”的情况就可以考虑使用defineAsyncComponent。它不是越多越好而是应该把异步加载留给那些体积较大、出现较晚、使用频率较低的组件。参考资料Vue 官方文档异步组件Vue 官方 APIdefineAsyncComponent