有关vue路由的学习

news2024/11/24 3:11:16

导言

由于很久没碰前端了,碰到路由都不太会了。趁着后端对接来记录一下,就当复习。不过由于个人能力有限,这篇会偏向整个过程的实现逻辑,其中有很多具体的方法不会给来,有兴趣的可以去看一下源码~

目的:

搞清楚若依路由侧边栏菜单生成及展示的逻辑

侧边栏菜单sidebar-item应用的数据格式,后端数据所必需的字段和格式

前端对后端传来数据的处理

逻辑:

1.整个菜单应用逻辑

       1.前端接受后端对应的格式数据。
       2.将其根据Element-ui的<el-menu>所需的格式及用户角色对应改造成适合的列表存vuex里。
       3.在相应的布局页面(...\src\layout\components\Sidebar\index.vue)从vuex取出数据应用。
       4.在侧边栏展示和vue路由管理的对应跳转可以实现点击菜单跳转到对应页面

整体过程

1.前端请求与接收

1.路由守卫调用GenerateRoutes

在...\src\permission.js,有token且不在登录页。

          store.dispatch('GenerateRoutes').then(accessRoutes => {
            // 根据roles权限生成可访问的路由表
            router.addRoutes(accessRoutes) // 动态添加可访问路由表
            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
          })

调的是...src\store\modules\permission.js的,名字一样。

这里调完之后会把处理好的路由塞进路由表里

2.GenerateRoutes:
// 生成路由
    GenerateRoutes({ commit }) {
      // 返回一个新的 Promise
      return new Promise(resolve => {
        // 向后端请求路由数据
        getRouters().then(res => {
          console.log("后端返回的数据:",res);
            ...
        });
      });
    }

主要是承担请求后端,改造数据和存数据到vuex的功能,代码2.数据改造有

3.请求方法:
// 获取路由
export const getRouters = () => {
  return request({
    headers: {
      isToken: true
    },
    url: 'api/Menus/GetUserMenus',
    method: 'get'
  })
}

2.数据改造及存储

在...\src\store\modules\permission.js

    // 生成路由
    GenerateRoutes({ commit }) {
      // 返回一个新的 Promise
      return new Promise(resolve => {
        // 向后端请求路由数据
        getRouters().then(res => {
          console.log("后端返回的数据:",res);
          
          // 深拷贝后端返回的路由数据
          const sdata = JSON.parse(JSON.stringify(res.data));
          const rdata = JSON.parse(JSON.stringify(res.data));
          

          // 过滤出适合侧边栏的路由
          const sidebarRoutes = filterAsyncRouter(sdata);
          
          // 过滤出重写的路由
          const rewriteRoutes = filterAsyncRouter(rdata, false, true);
          // 过滤出动态路由
          const asyncRoutes = filterDynamicRoutes(dynamicRoutes);

          
          // 添加一个重定向路由,处理未匹配的路径
          rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true });

          // 将动态路由添加到 Vue Router
          router.addRoutes(asyncRoutes);
          

          // 提交 mutations 更新路由状态
          commit('SET_ROUTES', rewriteRoutes);
          commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes));
          commit('SET_DEFAULT_ROUTES', sidebarRoutes);
          commit('SET_TOPBAR_ROUTES', sidebarRoutes);

          
          // 解析 Promise,返回重写的路由
          resolve(rewriteRoutes);
        });
      });
    }

其中的三类路由:

sidebarRoutes:这些路由用于生成侧边栏菜单。它们通常是与用户可视导航相关的路由,
因此侧边栏会根据用户的角色或权限显示不同的菜单结构。

rewriteRoutes:这些路由包含重写逻辑,主要用于处理应用中的实际导航和访问控制。
可以理解为对原始路由的一个“过滤”或“优化”,确保在需要时能够准确地导航或限制用户的访问。

asyncRoutes:这些路由仅在特定条件下加载。它们通常与权限控制相关,因此需要在运行时动态地添加到
 Vue Router。通过这种方式,可以在不重新加载页面的情况下,根据用户角色或权限控制对不同路由的访问。

3.侧边栏菜单数据应用:

在...\src\layout\components\Sidebar\index.vue侧边栏组件

数据来源sidebarRouters是拿GenerateRoutes存进vuex的侧边栏路由菜单

  //...\src\store\modules\permission.js
  SET_DEFAULT_ROUTES: (state, routes) => {
      state.defaultRoutes = constantRoutes.concat(routes)
    },
  //...\src\layout\components\Sidebar\index.vue
  ...mapGetters(["sidebarRouters", "sidebar"]),

这个组件定义了侧边栏的样式等,主要还是sidebar-item组件

<template>
    <div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
        <logo v-if="showLogo" :collapse="isCollapse" />
        <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">

    <el-menu
        :default-active="activeMenu"  
        :collapse="isCollapse"  
        :background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"  
        :text-color="settings.sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor" 
        :unique-opened="true" 
        :active-text-color="settings.theme"  
        :collapse-transition="false" 
        mode="vertical" 
    > 
    <!-- 遍历 sidebarRouters 数组,生成菜单项 --> 
     <!-- 使用路由路径和索引生成唯一的 key -->
      <!-- 将当前路由项传递给 sidebar-item 组件 --> 
       <!-- 将当前路由的路径传递给 sidebar-item 组件 -->
        <sidebar-item
            v-for="(route, index) in sidebarRouters" 
            :key="route.path  + index" 
            :item="route"  
            :base-path="route.path" 
        />
    </el-menu>
</el-scrollbar>

    </div>
</template>
菜单组件sidebar-item介绍及其所需要的东西
介绍:

sidebar-item是若依自定义的一个组件,在...\src\layout\components\Sidebar\SidebarItem.vue

用于展示单个菜单项(侧边栏)。

根据...\src\layout\components\Sidebar\index.vue传过来的item,isNest,basePath等来确定菜单的展示样式(是否展示,是否下拉...)

源码学习:

template,用hidden控制是否展示,之后分两部分

1.传来的菜单只有一个子菜单/没有子菜单:

    <!-- 判断是否只有一个显示的子项且满足其他条件 -->
    <!-- && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && 要么 onlyOneChild 没有子项,要么它的所有子项都不可见。 -->
    <template
      v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">

       <!-- 如果存在子项的 meta,使用 app-link 组件进行导航 -->
      <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)">
       
        <!-- 渲染一个菜单项,index 为子项的路径 -->
        <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }">
          
          <!-- 显示子项的图标和标题,如果没有图标,则使用父项的图标 -->
          <item :icon="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" :title="onlyOneChild.meta.title" />
          
        </el-menu-item>
      </app-link>
    </template>

这段的处理就相当于把没有子菜单的直接展示,把只有一个子菜单的直接显示子菜单

如下图,系统管理只有菜单管理一个子菜单,所以直接展示了菜单管理:

hasOneShowingChild方法分三种情况:

// 当存在且仅有一个可见的子项时:
// 如果 showingChildren.length === 1,则返回 true,表示有一个可显示的子项。

// 当没有可见子项时:
// 如果 showingChildren.length === 0,则会设置 this.onlyOneChild 为一个新的对象,且返回 true。这表示在没有显示的子项的情况下,父项仍然需要被显示。

// 如果有多个可见子项时:
// 如果有两个或更多可见子项,则返回 false,表示没有唯一的可显示子项。
    hasOneShowingChild(children = [], parent) {

      if (!children) {
        children = [];
      }
      const showingChildren = children.filter(item => {
        if (item.hidden) {
          return false
        } else {
          // Temp set(will be used if only has one showing child)
          this.onlyOneChild = item
          return true
        }
      })

      // When there is only one child router, the child router is displayed by default
      if (showingChildren.length === 1) {
        return true
      }

      // Show parent if there are no child router to display
      if (showingChildren.length === 0) {
        this.onlyOneChild = { ...parent, path: '', noShowingChildren: true }
        return true
      }

      return false
    },

2.第二部分:

绑定完当前菜单后嵌套调sidebar-item,循环绑该菜单项的子菜单

    <!-- 如果不满足上述条件,则渲染一个子菜单 -->
    <!-- :index 用于设置 <el-submenu> 组件的唯一标识符。这是一个字符串或路径,表示菜单项的唯一键,通常用于导航或路由。 -->
    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
      
      <template slot="title">
        <!-- 渲染子菜单的标题,如果存在 meta,则显示图标和标题 -->
        <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
      </template>
      <!-- :basepath 是一个自定义的 prop,用于传递子菜单项的基础路径。
       <sidebar-item> 组件中的 basepath 主要用于生成子项的相对路径,或者作为子项路径的起点。 -->
        <!-- 循环调用绑子菜单 -->
      <sidebar-item v-for="child in item.children" :key="child.path" :is-nest="true" :item="child"
        :basepath="resolvePath(child.path)" class="nest-menu" />-
    </el-submenu>

3.resolvePath方法

//用于解析并生成完整的导航路径
    resolvePath(routePath, routeQuery) {
      console.log("routePath",routePath);
      console.log("分割符");
      
      if (isExternal(routePath)) {//是外链
        return routePath
      }
      //如果 basePath 是外部链接,则返回 basePath。在这种情况下,
      //routePath 被忽略,最终导航会指向 basePath,这是因为 basePath 已经是一个完整的外部链接。
      if (isExternal(this.basePath)) {
        return this.basePath
      }
      // 如果提供了 routeQuery,则解析查询字符串,并生成包含 path 和 query 的对象:
      if (routeQuery) {
        let query = JSON.parse(routeQuery);
        //返回的对象包含 path 和 query 字段,以便在导航时附加查询参数,如字典数据
        return { path: path.resolve(this.basePath, routePath), query: query }
      }
      //如果 routeQuery 为空,且路径都为内部链接,则使用 path.resolve(this.basePath, routePath) 将 routePath 解析为基于 basePath 的完整路径。
      return path.resolve(this.basePath, routePath)
    }

4.有关alwaysShow

在路由表有相关介绍,我这没用这个

/**
 * Note: 路由配置项
 *
 * hidden: true                     // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
 * alwaysShow: true                 // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
 *                                  // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
 *                                  // 若你想不管路由下面的 children 声明的个数都显示你的根路由
 *                                  // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
...
 */
所需要的东西:

大概长这样:

侧边栏菜单和路由表的关系

  1. 数据来源:

    • 侧边栏菜单的构建通常基于路由表。路由表定义了所有可用的路由及其对应的组件、权限等信息。
    • 当从后端获取路由数据时,侧边栏菜单会根据这些数据生成相应的菜单项。
  2. 动态生成:

    • 当用户的权限发生变化(如角色变更)时,可能需要重新生成可访问的路由和侧边栏菜单。
    • 例如,GenerateRoutes 方法从后端获取路由数据后,通过权限过滤生成 accessRoutes,同时生成相应的侧边栏菜单。
  3. 结构一致性:

    • 侧边栏菜单和路由表通常遵循相同的数据结构。侧边栏菜单的每个菜单项通常会对应路由表中的一条路由,这样在导航时可以确保用户点击菜单后,能够正确匹配到相应的组件。
  4. 管理与更新:

    • router.addRoutes(accessRoutes) 中,动态添加可访问的路由表。这意味着应用程序的路由结构是可变的,可以根据用户的角色和权限动态更新。
    • 同时,更新路由表后,侧边栏菜单也会根据新的路由数据进行重新渲染,以反映最新的导航结构。
  5. 导航功能:

    • 用户通过侧边栏菜单进行导航,实际背后的路由表则决定了哪些组件被加载和渲染。因此,侧边栏菜单的可用性和功能直接依赖于路由表的配置。

      侧边栏菜单是用户与应用程序交互的界面,而路由表则是管理应用程序导航和组件渲染的核心结构。两者通过相同的数据模型和动态更新机制,保持一致性和功能性。

总结:

搞了很多天,主要还是基础和思路,很多时间都不知道自己在干嘛,其中的很多细节都还没搞懂,不过写了这篇,也大概能捋一下思路。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2210084.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能驾驶|迈向智能出行未来,AI如何应用在自动驾驶?

自动驾驶通过人工智能&#xff08;AI&#xff09;、机器学习、传感器融合和实时数据处理&#xff0c;使车辆能够在无需人类干预的情况下自主驾驶。随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;与智能汽车的结合正在成为现代交通运输领域的热潮。无人驾驶…

数学建模算法与应用 第14章 综合评价与决策方法

目录 14.1 层次分析法&#xff08;AHP&#xff09; Matlab代码示例&#xff1a;层次分析法权重计算 14.2 模糊综合评价法 Matlab代码示例&#xff1a;模糊综合评价法 14.3 灰色关联分析法 Matlab代码示例&#xff1a;灰色关联分析 14.4 主成分分析法&#xff08;PCA&…

SAP HCM 并发后台作业,解决考勤评估慢问题

这几天遇到刷卡分离程序需要跑很长时间&#xff0c;严重影响后面的时间评估与推送SucessFactors的考勤异常信息&#xff0c;下图是刷卡分离程序耗时时间&#xff0c;16个小时 记得原来算几万员工工资的时候SAP提供一个标准的并发后台程序RPCS0000&#xff0c;就是核算几万人的工…

MySQL 的数据类型

1.整数类型 1.1 tinyint tinyint 为小整数类型&#xff0c;存储空间为1个字节&#xff08;8位&#xff09;&#xff0c;有符号范围-128 ~ 127&#xff0c;无符号范围 0 ~ 255,此类型通常在数据库中表示类型的字段&#xff0c;如某一字段 type 表示学科,其中 “type1” 表示语文…

Fetch 与 Axios:JavaScript HTTP 请求库的详细比较

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…

一起体验AI动手实验,OceanBase 2024 年度发布会精彩预告

2024年OceanBase年度发布会将于10月23日在北京望京凯悦酒店举行。此次大会围绕“不止于记录”的主题&#xff0c;共同探讨当前数据库领域的前沿话题&#xff0c;包含主论坛、分论坛、AI 动手实训营、开源技术交流会等多个环节&#xff0c;诚邀全国各地的企业和开发者共同参与&a…

系统架构设计师考试背记精要

1、架构的本质&#xff1a; &#xff08;1&#xff09;软件架构为软件系统提供了一个结构、行为和属性的高级抽象。&#xff08;2&#xff09;软件架构风格是特定应用领域的惯用模式&#xff0c;架构定义一个词汇表和一组约束。 2、数据流风格&#xff1a;适合于分阶段做数据处…

记录使用appium+夜神模拟器测试多设备时selenium和appium版本不兼容带来的问题

记录使用appium夜神模拟器测试多设备时selenium和appium版本不兼容带来的问题 好不容易解决了selenium和appium的版本冲突问题&#xff08;导致&#xff1a;AttributeError: ‘NoneType’ object has no attribute to_capabilities’异常发生&#xff09; 第二天运行代码发现…

24/10/12 算法笔记 NiN

LeNet、AlexNet和VGG都有一个共同的设计模式&#xff1a;通过一系列的卷积层与汇聚层来提取空间结构特征&#xff1b;然后通过全连接层对特征的表征进行处理。 AlexNet和VGG对LeNet的改进主要在于如何扩大和加深这两个模块。 或者&#xff0c;可以想象在这个过程的早期使用全连…

D35【python 接口自动化学习】- python基础之输入输出与文件操作

day35 文件合并 学习日期&#xff1a;20241012 学习目标&#xff1a;输入输出与文件操作&#xfe63;-47 如何使用python合并多个文件&#xff1f; 学习笔记&#xff1a; 合并文件需求分析 合并两个文件 代码实现 # 合并两个文件 with open(demo1.txt) as f1:file_data_1f…

Clickhouse 安装部署说明手册

Clickhouse 安装部署说明手册 准备工作 操作系统 CentOS Linux release 7.5.1804 详细信息&#xff1a; LSB Version: :core-4.1-amd64:core-4.1-noarch:cxx-4.1-amd64:cxx-4.1-noarch:desktop-4.1-amd64:desktop-4.1-noarch:languages-4.1-amd64:languages-4.1-noarch:pr…

【LeetCode】动态规划—95. 不同的二叉搜索树 II(附完整Python/C++代码)

动态规划—95. 不同的二叉搜索树 II 题目描述前言基本思路1. 问题定义二叉搜索树的性质&#xff1a; 2. 理解问题和递推关系递归构造思想&#xff1a;状态定义&#xff1a;递推公式&#xff1a;终止条件&#xff1a; 3. 解决方法递归 动态规划方法&#xff1a;伪代码&#xff…

Linux高级编程_32_磁盘映射

文章目录 磁盘映射相关函数mmap函数作用&#xff1a; munmap函数作用&#xff1a; truncate 函数作用&#xff1a; 语法&#xff1a;使用步骤&#xff1a; 磁盘映射 概述&#xff1a; > 存储映射 I/O (Memory-mapped I/O) 使一个磁盘文件与存储空间中的一个缓冲区相映射。…

Excel中Ctrl+e的用法

重点&#xff1a;想要使用ctrle&#xff0c;前提是整合或拆分后的结果放置的单元格必须和被提取信息的单元格相邻&#xff0c;且被提取信息的单元格也必须相连。 下图为错误示例 这样则可以使用ctrle 1、信息整合 2、提取信息 3、添加符号 4、信息顺序调换 5、数字提取 crtle还…

AI测试之 TestGPT

如今最火热的技术莫非OpenAI的ChatGPT莫属&#xff0c;AI技术也在很多方面得到广泛应用。今天我们要介绍的TestGPT就是一个软件测试领域中当红的应用。 TestGPT是什么&#xff1f; TestGPT是一家总部位于以色列特拉维夫的初创公司 CodiumAI Ltd.&#xff0c;发布的一款用于测…

Android:记录一个打包发布版的release包以后闪退的问题

个人感觉其实release闪退的问题挺难排查的&#xff0c;因为release包运行起来as捕获不到相应的应用程序进程&#xff0c;从而不易查看到日志&#xff0c;也是我玩得不溜&#xff0c;大家有不同的方法可以评论区探讨&#xff0c;我也定期回复一些评论一起讨论。以下是我遇到的情…

高效的读书与笔记管理:打造个人知识体系

01 读书学习的常见问题 1、读书⼯具分散&#xff0c;划线和笔记分散&#xff0c;导致我们的复习、搜索效率低。⽐如不同书籍中&#xff0c;提到了同⼀个问题的观点&#xff0c;很难进行关联。 2、读书&#xff0c;仅限于读&#xff0c;知道别⼈的观点&#xff0c;但是缺乏内…

【AI论文精读13】RAG论文综述2(微软亚研院 2409)P5-可解释推理查询L3

AI知识点总结&#xff1a;【AI知识点】 AI论文精读、项目、思考&#xff1a;【AI修炼之路】 P1&#xff0c;P2&#xff0c;P3&#xff0c;P4 五、可解释推理查询&#xff08;L3&#xff09; ps&#xff1a;P2有四种查询&#xff08;L1&#xff0c;L2&#xff0c;L3&#xff0c;…

学习记录:js算法(六十二):单词搜索 II

文章目录 单词搜索 II思路一思路二 单词搜索 II 给定一个 m x n 二维字符网格 board 和一个单词&#xff08;字符串&#xff09;列表 words&#xff0c; 返回所有二维网格上的单词 。 单词必须按照字母顺序&#xff0c;通过 相邻的单元格 内的字母构成&#xff0c;其中“相邻”…

crashrpt3 开源项目的Vs 2022 C++20及其以上的编译

1. 首先从github 下载源代码 crashrpt3 2. 用CMake Gui 编译成vs studio 工程文件 2.1 点击 config 按钮 2.2 依次点击 Generate 按钮、Open Project 按钮.之后vs 2022 会打开编译好的sln工程文件 3.全选解决方案里面的所有项目,设置C语言标准,我这里设置是最新C,即启用的是…