×

Vue每日一学:通过实例聊聊如何实现动态路由

作者:Terry2023.06.09来源:Web前端之家浏览:3332评论:0
关键词:vuejs

今天学一个Vue小应用:通过实例聊聊如何实现动态路由。我们在项目开发的过程中,难免会使用路由,那么我们在开发多角色的时,由于每个角色的权限不同,因此访问到的页面肯定也要有所限制,这个时候我们就需要使用动态路由,先看个效果图:

image.png

当改变url路径的时候,右边的页面会随之变化数据和显示。如何实现呢?往下看吧。

使用的技术栈

  • 使用了koa2来作为后端

  • 使用vuex实现全局的数据共享

  • vue3的语法

  • 当然这里面还会使用一些算法(递归算法)

首先使用 vue create project-name 创建项目

后端使用koa2 项目名称 从创建项目

实现思路

首先我们先来捋一下实现的思路:

  • 后端需要设计数据,这个数据包含路由的路径path,id ,pid(该路由的父级路由id),title 这里面是要显示的内容

  • 同样我们在前端可以模拟登录,创建几个用户,然后我们给用户设计的字段可以是这样的 id(用户id),name(用户姓名)

  • auth(权限设置,是一个数组,表明可以访问的路由的id)

  • 前端通过axios来访问后端的数据,然后获取数据之后前端将其树形化(使用递归算法),然后我们可以将其转换为动态的路由结构(这部分可以封装一个工具函数来实现)

  • 我们可以借助vuex来实现axios的异步请求,通过mutations来将值赋值给state中定义的数据。这样我们就可以实现全局的数据共享。

具体实现

首先我们来设计数据

这部分是路由菜单:

  1. module.exports = [
  2.   {
  3.     id: 1,
  4.     pid: 0, //pid为0表明为顶层
  5.     path: "/course",
  6.     name: "Course",
  7.     title: "课程管理",
  8.   },
  9.   {
  10.     id: 2,
  11.     pid: 1,
  12.     path: "operate",
  13.     name: "CourseOperate",
  14.     Link: "course/operate",
  15.     title: "课程操作",
  16.   },
  17.   {
  18.     id: 5,
  19.     pid: 0,
  20.     path: "/student",
  21.     name: "Student",
  22.     title: "学生管理",
  23.   },
  24.   {
  25.     id: 6,
  26.     pid: 5,
  27.     path: "operate",
  28.     name: "StudentOperate",
  29.     Link: "/student/operater",
  30.     title: "学生操作",
  31.   },
  32.   ...
  33. ];

当然这里面我只展示部分数据,其实可以依次类推,我们不难发现,pid是父级路由的id,这样做就是为了后期将数据加工成树形结构。

用户的数据:

  1. module.exports = [
  2.   {
  3.     id: 1,
  4.     name: "张三",
  5.     auth: [1, 2, 5, 6],
  6.   },
  7.   {
  8.     id: 2,
  9.     name: "李四",
  10.     auth: [1, 2, 4, 5, 6, 7],
  11.   },
  12.   {
  13.     id: 3,
  14.     name: "王五",
  15.     auth: [1, 2, 3, 4, 5, 6, 7],
  16.   },
  17. ];

正如我们之前所说,这个用户id包含这几个字段,其中auth这个字段无疑是最重要的,他是一个数组,里面存的时路由的id,表明为用户的访问权限。

封装一下axios函数

在这个小的项目里面,我们需要使用aixos函数来请求后端的数据,那么我们和不妨封装一个请求函数,这样更方便我们请求后端的数据

  1. import axios from "axios";
  2. import qs from "qs";
  3. //这里面的uid是要传入的用户id值
  4. function getUserRouters(uid) {
  5.   return axios({
  6.     url: "http://localhost:3000/user_router_auth",
  7.     method: "post",
  8.     headers: {
  9.       "Content-Type": "application/x-www-form-urlencoded",
  10.     },
  11.     data: qs.stringify({ uid }),
  12.   })
  13.     .then((res) => {
  14.       return res.data;
  15.     })
  16.     .catch((err) => {
  17.       throw err;
  18.     });
  19. }
  20. export { getUserRouters };

其中url是后端的接口,data代表要传递的数据,qs.stringify表明将uid转换为json字符串。这个封装的函数最终会返回一个Promise.then()。

使用vuex实现全局数据共享

action部分

用来做异步请求,获取后端的数据,并且将其进行树形化处理。

  1. import { getUserRouters } from "@/service";
  2. import { toTreeList } from "@/utils/utils";
  3. export default {
  4.   async setUserRouters({ commit, state }) {
  5.     // 使用axios获取数据
  6.     const userRouters = await getUserRouters(state.uid);
  7.     // 将获取到的后端数据树形化
  8.     const list = toTreeList(userRouters);
  9.     console.log(list);
  10.     commit("setAuth", true);
  11.     commit("setUserRouters", list);
  12.   },
  13. };

mutations部分:

将获取到的数据存放在state中,便于进行全局访问。

  1. export default {
  2.   // 更改权限
  3.   setAuth(state, Auth) {
  4.     state.hasAuth = Auth;
  5.   },
  6.   // 将数据存储在state中
  7.   setUserRouters(state, userRouters) {
  8.     state.TreeList = userRouters;
  9.   },
  10. };

state部分

  1. export default {
  2.   uid: 1,
  3.   hasAuth: false,
  4.   TreeList: [],
  5. };

将数据转化为树形化结构

  1. function toTreeList(list, id = 0) {
  2.   let res = [];
  3.   list.forEach((item) => {
  4.     if (item.pid === id) {
  5.       item.children = toTreeList(list, item.id);
  6.       //   这一步是为了是最里层的children会是空,应该删除
  7.       if (item.children.length == 0) delete item.children;
  8.       res.push(item);
  9.     }
  10.   });
  11.   return res;
  12. }

思路:

在这个封装函数里面使用到了递归的思想,我们在设计数据的时候给每一个数据都设计了id和pid,那么最顶层元素的pid为0(没有父级元素),其他子级都拥有pid,所以我们可以这样操作,设计一个函数,默认传入从后端获取到的数据list,和最顶层元素pid值(默认为0),然后我们对list进行遍历,判断list中的元素item的pid值与id是否相等,如果相等,那么item.children=toTreeList(list,item.id)来进行递归调用,这样当pid和id值不相同时,就会执行res.push(item)将元素push到res里面。

基础路由模块

  1. import { createRouter, createWebHashHistory } from "vue-router";
  2.  
  3. const routes = [
  4.   {
  5.     name: "home",
  6.     path: "/",
  7.     component: () => import("../views/Home.vue"),
  8.   },
  9.   {
  10.     name: "NotFound",
  11.     path: "/:pathMatch(.*)*",
  12.     component: () => import("../views/NotFound.vue"),
  13.   },
  14. ];
  15.  
  16. const router = createRouter({
  17.   history: createWebHashHistory(),
  18.   routes,
  19. });
  20.  
  21. export default router;

当输入的路径不存在时就会跳转到NotFound这个组件显示这个页面

实现动态路由

  1. function generateRouter(userRouters) {
  2.   let newRouters = userRouters.map((r) => {
  3.     let routes = {
  4.       path: r.path,
  5.       name: r.name,
  6.       component: () => import(`@/views/${r.name}`),
  7.     };
  8.     if (r.children) {
  9.       routes.children = generateRouter(r.children);
  10.     }
  11.     return routes;
  12.   });
  13.   return newRouters;
  14. }

其中传入的userRouters是经过树形化处理的数据,同样这里面还是需要进行递归调用,这里对路由进行了配置,包括路由的路径,名称,都从后端获取。然后判断传入的树形结构数据是否含有子元素,如果有就递归调用给routes追加children,然后将处理过的routes返回,最后再将newRouters返回。

在main.js中配置路由守卫

  1. import router from "./router";
  2. import store from "./store";
  3. import { generateRouter } from "./utils/utils";
  4. // 配置路由守卫
  5. router.beforeEach(async (to, from, next) => {
  6.   if (!store.state.hasAuth) {
  7.     await store.dispatch("setUserRouters");
  8.     // 获取树形权限路由
  9.     const newRoutes = generateRouter(store.state.TreeList);
  10.     console.log(store.state.TreeList);
  11.     newRoutes.forEach((route) => {
  12.       router.addRoute(route);
  13.     });
  14.     next({ to: to.path });
  15.   } else {
  16.     next();
  17.   }
  18. });

首先通过调用actions中的方法,在actions中根据当前用户的id来异步请求数据,然后在actions的方法中会调用mutations的方法将数据存储到state中,然后再调用generateRouter方法获取路由,在对获取的路由数组通过遍历调用addRoute来动态的添加路由。

总结 

通过这次对动态路由的小案例的完成,使我对vue-router有了一个更深的认知,以及在实际项目中对于动态路由的实现都有了一个基本的思路,并且也学会了如何使用递归来将数据转化为树形结构的数据。

您的支持是我们创作的动力!
温馨提示:本文作者系Terry ,经Web前端之家编辑修改或补充,转载请注明出处和本文链接:
https://jiangweishan.com/article/vuejs20230609.html

网友评论文明上网理性发言 已有0人参与

发表评论: