在开始之前,提供先介绍一下我们目前新项目的可制采用的技术栈 没错,我们现在都采用 ts + jsx 语法来开发新项目,定化的路这里可能会有小伙伴说了,由加不用 template 吗,载方装啥装。提供这里面要讨论内容很多,可制下次有机会在分享,定化的路今天不讨论这个问题。由加 回到正文~~ 这个月老大在技术优化上(前端公共库)派了几个任务给我,载方其中的提供一个是"路由注册改造,采用组件内的可制异步加载",大家一看,定化的路肯定会想,由加就这?载方,这个不是配合 router.beforeEach 和 router.afterEach 在加个显示进度条的库 NProgress 不就完事了嘛。没错,就是按传统的方式会有一些问题,后面会讲,这里我们先来看传统方式是怎么做的。香港云服务器 这个方法大家应该都用过,就是在路由切换的时候,顶部显示一个加载的进度条,我们这里借助的库是 NProgress。 第一步,需要安装插件: 第二步,main.ts中引入插件。 第三步,监听路由跳转,进入页面执行插件动画。 路由跳转中 跳转结束 很简单的一个配置,运行后,当我们切换路由时就会看到顶部有一个进度条了: 这种模式存在两个问题(目前能想到的): 我们模拟一下弱网络,打开浏览器控制台,切到 NetWork,网络换成** Slow 3G**,然后在切换路由,下面是我实操的效果: 可以看到,我们切换到菜单二时,进度条件会慢慢走,页面没有及时切换到菜单二的界面,如果页面内容越多,效果越明显。 我们再来模拟一下网络断开的情况,切到 NetWork,网络换成** Offline**,然后在切换路由,下面是我实操的效果: 会看到在没有网络的情况下,进度条件还是在那一直转,站群服务器一直加载,没有及时的反馈,体验也是很差的。 我们团队想要的效果是: 为了解决上面的问题,我们需要一种能异步加载并且能自定义 loading 的方法,查阅了官方文档,Vue2.3 中新增了一个异步组件,允许我们自定义加载方式,用法如下: 注意如果你希望在 Vue Router 的路由组件中使用上述语法的话,你必须使用 Vue Router 2.4.0+ 版本。 但我们现在是使用 Vue3 开发的,所以还得看下 Vue3 有没有类似的方法。查阅了官方文档,也找到了一个方法 defineAsyncComponent,用法大概如下: 但在官方 V3 迁移指南中 官方有指出下面这段话: 官网说不应该使用defineAsyncComponent来做路由懒加载,但没说不能使用,而我们现在需要这个方法,所以还是选择用了(后面遇到坑在分享出来)。 有了上面的方法,我们现在的思路就是重写 Vue3 中的 createRouter方法,在createRouter 我们递归遍历传进来的 routes, 判断当前的组件是否是异步加载组件,如果是我们用 defineAsyncComponent方法给它包装起来。 下面是我现在封装的代码: 上面重写了 createRouter 方法,并提供了可选的配置参数 routerOptions,routerOptions里面的字段其实就是defineAsyncComponent里面了的参数,除了 loder。 有了现在的 createRouter,我们来看相同场景,不同效果。 可以看到第二种方案在弱方案的情况下,只要我们切换路由,页面也会马上进行切换,过渡方式也是采用我们指定的。不像第一种方案一样,页面会停在点击之前的页面,然后在一下的刷过去。 当切换到菜单时,因为这里我指定的时间 timeout 为 3 秒,所以在3秒内如果没有加载出来,就会显示我们指定的 errorComponent。 现在,打开浏览器,切到 NetWork,网络换成** Offline**,也就是断网的情况,我们在来看下效果。 可以看到,当我们网络断开的时候,在切换页面时,会显示我们指定 errorComponent,不像第一种方式一样会一直卡在页面上加载。 下面来看看,我事例路由: 我们现在想用下面已经封装好的冒泡加载方式来代替菊花的样式: 很简单,我们只需要把对应加载组件(BubbleLoading)的名称,传给 createRouter 既可,为了演示效果,我们把网络切花到 Slow 3G,代码如下: 如果我们只要点击菜单二才用 BubbleLoading ,点击其它的就用菊花的加载,那又要怎么做呢? 这里,大家如果认真看上面二次封装的 createRouter 方法,可能就知道怎么做了,其中里面有一个判断就是 其实我做的就是判断如果外面传进来的路由采用的异步加载的方式,我才对用 defineAsyncComponent 重写,其它的加载方式我是不管的,所以,我们想要自定义各自的加载方式,只要用 defineAsyncComponent 重写即可。 回到我们的 router.ts 代码, 在上面,我们用defineAsyncComponent定义菜单二的 component加载方式,运行效果如下: 从图片可以看出点击菜单一和三时,我们使用菊花的加载方式,点击菜单二就会显示我们自定义的加载方式。 这里有一个显性的 bug,就是下面代码: 不能用函数的方式来写,如下所示: 这里因为我在 createRouter 方法中使用 typeof childrenRoute.component === function来判断,所以上面代码又会被defineAsyncComponent包起来,变成两层的defineAsyncComponent,所以页面加载会出错。 我也想解决这个问题,但查了很多资料,没有找到如何在方法中,判断方法采用的是defineAsyncComponent 方式,即下面这种形式: 本文到这里就分享完了,我是刷碗智,我们下期见~背景
传统方式
弱网络
网络断开
我们想要啥效果
寻找解决方案
思路
弱网络
网络断开
变换 Loading
router.ts
import { RouteRecordRaw, RouterView, createWebHistory } from vue-router import { RouteRecordMenu } from @ztjy/antd-vue/es/components/AdminLayout import { AdminLayout, Login } from @ztjy/antd-vue-admin import createRouter from ./createRoute export const routes: RouteRecordMenu[] = [ { path: /menu, name: Menu, component: RouterView, redirect: /menu/list, meta: { icon: fas fa-ad, title: 菜单一, }, children: [ { path: /menu/list, component: () => import(@/pages/Menu1), meta: { title: 列表, }, }, ], }, { path: /menu2, name: Menu2, component: RouterView, redirect: /menu2/list, meta: { icon: fas fa-ad, title: 菜单二, }, children: [ { path: /menu2/list, component: () => import(@/pages/Menu2), meta: { title: 列表, }, }, ], }, { path: /menu3, name: Menu3, component: RouterView, redirect: /menu3/list, meta: { icon: fas fa-ad, title: 菜单三, }, children: [ { path: /menu3/list, component: () => import(@/pages/Menu3), meta: { title: 列表, }, }, ], }, ] const router = createRouter({ history: createWebHistory(/), routes: [ { path: /login, component: Login, props: { title: 商化前端后台登录, }, }, { path: /, redirect: /menu, component: AdminLayout, props: { title: 商化前端 后台 模板, routes, }, meta: { title: 首页, }, children: routes as RouteRecordRaw[], }, ], }) export default router router.ts
/***这里省略很多字**/ const router = createRouter( { history: createWebHistory(/), routes: [ /***这里省略很多字**/ ] }, { loadingComponent: BubbleLoading, // 看这里看这里 } ) export default router 花里胡哨
注意