前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >BuildAdmin05:如何玩转Vue路由动态加载

BuildAdmin05:如何玩转Vue路由动态加载

原创
作者头像
叫我阿柒啊
修改2024-06-11 17:16:37
5390
修改2024-06-11 17:16:37
举报
文章被收录于专栏:vue前端之路入门到放弃之路

关键字:BuildAdmin、vue-router、路由、Vue、ElementUI

前言

首先,在BuildAdmin中讲的路由,指的就是vue-router

vue-router在BuildAdmin中主要实现了菜单栏tabs标签页两大模块,而这两个模块是比较复杂的,所以对vue-router需要有一个很好的掌握。

此系列文章是面向BuildAdmin的,所以就从项目角度触发,来学习什么是路由、如何用路由。

什么是路由

路由器大家都听过吧,你电脑、手机都连这路由器和别人聊天。对面给你发了一条消息,先到路由器,路由器然后再转发给你的电脑或者手机上。那么到底是发到电脑还是手机上,路由器是通过IP决定发送到手机和电脑上。(可能说的不够专业)

在前端中,url中的路径就相当于上面的IP,一个个vue页面就相当于手机、电脑,前端页面根据路径(IP)就能找到对应的页面(手机、电脑)进行渲染。

上面是vue-router官网给出的最基本的用法,router-link就相当于\<a>,to指向的就是url路径path。然后在js中定义path与页面的对应关系,可以看到about对应的是About页面,/对应的是Home页面。

router-view就会根据触发的router-link,来决定是将Home还是About页面加载渲染。

可以看到,url中的路径随着页面而变化。

vue-router

官网地址:https://router.vuejs.org

首先了解一下路由有哪些功能,其次,再去再去使用路由?

我们使用比较多的就是动态路由、路由模式和导航。

接着明确项目需要一个什么样的路由,是静态路由还是动态路由。

静态路由

上面官网给出的样例,就是静态路由的写法。静态路由扩展性差,将路由规则写在vue组件中,想要增加/删除只能修改代码、然后重新发布。

动态路由

而动态路由是从后台API请求,然后通过调用vue-router的api(例如addRoute),动态解析渲染到routes属性中,BuildAdmin中的侧边栏menu,就是通过动态路由实现的。这样新增/删除只需要将路由信息,存到数据库即可。

1. 初始化路由对象

在BuildAdmin中,路由没有写在某一个vue组件中,而是将其独立成一个router模块。一些静态路由定义在了@/router/static.ts中,例如首页、404页面这些路由信息。

然后调用createRouter来创建一个全局路由对象router,将路由信息(staticRoutes)绑定在router上。

2. 后台请求路由信息

侧边栏的菜单就是动态路由渲染。从后台请求路由信息,以json格式返回给前端代码,实现动态加载,从控制台可以看到请求数据。

如果我需要新增一个Vue页面,只需要把这个vue文件放到项目的目录中,然后在数据库中新增一条路由信息。

动态加载路由

在BuildAdmin中,处理动态路由的代码还是挺多的,主要封装在@/util/router.js中,一共399行代码。我根据自己的需求,重构、重写了方法,然后与BuildAdmin的代码学习印证。

动态加载路由,主要是使用router的 addRoute() 方法,添加一条新的路由记录到router对象的routes属性中。

1. 获取路由信息

BuildAmin中的路由信息是通过axios请求api从后台获取的。因为我还没有写到后台,所以这里就把json直接拿过来,定义了一个变量来模拟获取。

为了更好理解下面的操作,我将json贴出来。

代码语言:javascript
复制
export const routesList = {
    code: 1,
    time: 1685431878,
    menus: [{
        "id": 1,
        "pid": 0,
        "type": "menu",
        "title": "控制台",
        "name": "dashboard/dashboard",
        "path": "dashboard",
        "icon": "fa fa-dashboard",
        "url": "",
        "component": "views/AboutView",
        "keepalive": "AboutView",
        "menu_type": "tab",
        "extend": "none"
    },
        {
            "id": 2,
            "pid": 0,
            "type": "menu_dir",
            "title": "权限管理",
            "name": "auth",
            "path": "auth",
            "icon": "fa fa-group",
            "url": "",
            "component": "",
            "keepalive": 0,
            "extend": "none",
            "menu_type": null,
            "children": [
                {
                    "id": 3,
                    "pid": 2,
                    "type": "menu",
                    "title": "角色组管理",
                    "name": "auth/group",
                    "path": "auth/group",
                    "icon": "fa fa-group",
                    "url": "",
                    "component": "views/HomeView",
                    "keepalive": "HomeView",
                    "menu_type": "tab",
                    "extend": "none",
                },
                {
                    "id": 8,
                    "pid": 2,
                    "type": "menu",
                    "title": "管理员管理",
                    "name": "auth/admin",
                    "path": "auth/admin",
                    "icon": "el-icon-UserFilled",
                    "url": "",
                    "component": "views/HomeView",
                    "keepalive": "HomeView",
                    "menu_type": "tab",
                    "extend": "none",
                }
            ]
        }]
}

2. 处理路由信息

定义handleMenuRule方法,将json路由信息处理成一条条路由数据(RouteRecordRaw),放入menuRule数组并返回。

打印查看menuRule。

可以可到menuRule现在已经是一个数组了,具有path和component属性,而且path统一增加了admin前缀,用来区分模块。

此时这里的component还是个字符串,当前只表示vue文件的路径。我们要想将字符串变成vue的component,就需要加载component。

3.动态加载路由

我们看看静态路由是如何加载vue component的。

代码语言:javascript
复制
  {
        path: '/404',
        name: '404',
        component: () => import('@/views/common/404.vue'),
    }

使用一个懒加载,当触发这个路由时,才会import加载。在BuildAdmin使用vite提供方法,将路由中的一个个component全量加载。

但我使用的是webpack,没有全量加载的功能,只能使用import逐个进行加载。我在这里定义了一个addAllRoute() 方法。

这里遍历menuRule调用router.addRoute() 方法,menu_type为tab的路由添加进去(因为有些路由只是目录,是用来表示层级关系的),如果这个路由下面有子路由,则进行递归。

你会有疑问?为什么 import() 的参数那么奇怪呢?因为,webapck中用于引入component的import的参数,是不支持 完全使用变量 的,也就是必须有字符串。可以来测试一下:

代码语言:java
复制
// 方式一:固定字符串,正常运行
() => import("@/views/AboutView.vue")

// 方式二:全变量,报错
const component = "@/views/AboutView.vue"
()=> import(component)

// 方式三:字符串 + 变量,正常运行。
const component = "views/AboutView"
()=> import(`@/${component}.vue`)

起始路径一定要是字符串,即@/,文件后缀也要是字符串,这样Typescript才能解析。

方式二报错信息如下:

我们再看看router对象路由在动态加载前和加载后的区别。

可以看到多了新增的三条路由。到这里你会发routes和menuRule的层级不一样,menuRule最后两个路由是是放在同一个父路由下的。

如果这样实现的话,就需要调用addRoute(parent, router),我使用这种方法一直无法实现动态加载,后来就另辟蹊径就直接将路由全都放到一个层级,反正渲染菜单时用的是menuRule的层级关系,只要menuRule和routes中的path保持一直就可以了。

4. 更新路由全局状态

然后开发一个对其他模块开放的handleAdminRoute方法,用来执行addRouteAll来动态加载路由。

在动态加载完路由之后,还将menuRule放到了useNavTabs的tabsViewRoutes中。useNavTabs是pinia(类似于vuex)定义的状态,用于全局访问。

这里的tabsViewRoutes主要用来渲染aside的菜单。

5. 渲染菜单

调用handleAdminRoute之后,router的路由和tabsViewRoutes都初始化完成。在menu中传递给用于构建目录结构的子组件menuTree。

menuTree通过props接收父组件传过来的参数,然后遍历路由渲染菜单结构。

如果有children子路由的话,是渲染成目录,即el-sub-menu,只有一条路由信息中最底层的路由,才会渲染成路由,即el-menu-item。

可以看到,”权限管理“只是一个目录,”控制台“是一个路由。

6. 路由跳转

在静态路由中,是通过router-link(类似于a)的to属性来进行跳转,菜单栏没有to属性,那怎么跳转。同样,这里也是通过编程式来进行跳转。定义onClickMenu方法使用route.push()来进行路由的跳转。

7. 路由渲染

在路由跳转之后,就会加载对应的component到router-view中。我想将component页面加载到中间区域,那么我就在main中定义router-view标签。

至于里面的keep-alive这一系列标签,后面都会讲到。

路由bug

其实写到这里这里的时候,就遇到一个bug(后面会解决)。

我点击了某一个路由,然后刷新浏览器,就会提示无法匹配这个路由,main区域就没有页面显示,然后显示404,并跳转到上一个页面。

这个问题是刷新时,后台路由还没有动态加载导致的,以后有了后台,用api向后台请求路由信息就能解决这个问题。在后面Loading页面的实现时,我加了一条路由就把这个问题解决了,这里就先不纠结这个问题。

至于为什么为跳转到上个路由,是因为加载404之后,调用了router.back回到上个路由。

结语

本篇文章主要讲述了我在项目中,是如何使用vue-router动态加载的,初次使用,经验尚浅,请各位不吝赐教。

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 什么是路由
  • vue-router
    • 静态路由
      • 动态路由
        • 1. 初始化路由对象
        • 2. 后台请求路由信息
    • 动态加载路由
      • 1. 获取路由信息
        • 2. 处理路由信息
          • 3.动态加载路由
            • 4. 更新路由全局状态
            • 5. 渲染菜单
            • 6. 路由跳转
            • 7. 路由渲染
        • 路由bug
        • 结语
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档