首页 前端知识 大数据毕业设计之前端06:Vue菜单路由动态加载是如何实现的

大数据毕业设计之前端06:Vue菜单路由动态加载是如何实现的

2024-07-20 17:07:16 前端知识 前端哥 275 501 我要收藏

前言

首先,在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贴出来。

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的。

  {
        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的参数,是不支持 完全使用变量 的,也就是必须有字符串。可以来测试一下:

// 方式一:固定字符串,正常运行
() => 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实现路由的。

转载请注明出处或者链接地址:https://www.qianduange.cn//article/14052.html
标签
大数据
评论
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!