16vue3实战-----动态路由

16vue3实战-----动态路由

  • 1.思路
  • 2.实现
    • 2.1创建所有的vue组件
    • 2.2创建所有的路由对象文件(与上述中的vue文件一一对应)
    • 2.3动态加载所有的路由对象文件
    • 2.4根据菜单动态映射正确的路由
    • 2.5解决main页面刷新的问题
    • 2.6解决main的第一个页面匹配显示的问题
    • 2.7根据path匹配menu

1.思路

思路可以看我写的另外一篇文章https://blog.csdn.net/fageaaa/article/details/145559821中的4.2(2)。那篇文章是以vue2为例,但思路差不多,只不过vue2和vue3中一些代码的书写有所不同。

2.实现

2.1创建所有的vue组件

在这里插入图片描述

2.2创建所有的路由对象文件(与上述中的vue文件一一对应)

在这里插入图片描述
路由对象文件内部内容,以main/user/user.ts为例:

export default {
  path: '/main/system/user',
  component: () => import('@/views/main/system/user/user.vue')
}

2.3动态加载所有的路由对象文件

可能有些公司没有把每个路由信息分别保存在各个文件,而是直接在一个文件中直接聚集,这样子当然也不会有问题。这里我是让每个ts文件就保存自己的路由信息,直接自动化读取。
把这个功能提取到utils工具文件夹中,新建map-menus.ts:
在这里插入图片描述
utils/map-menus.ts:

import type { RouteRecordRaw } from 'vue-router'
function loadLocalRoutes() {
  // 1.动态获取所有的路由对象, 放到数组中
  // * 路由对象都在独立的文件中
  // * 从文件中将所有路由对象先读取数组中
  //RouteRecordRaw[]这种类型根据提示可以知道
  const localRoutes: RouteRecordRaw[] = []

  // 1.1.读取router/main所有的ts文件
  const files: Record<string, any> = import.meta.glob(
    '../router/main/**/*.ts',
    {
      eager: true
    }
  )
  // 1.2.将加载的对象放到localRoutes
  for (const key in files) {
    const module = files[key]
    localRoutes.push(module.default)
  }
  return localRoutes
}

2.4根据菜单动态映射正确的路由

utils/map-menus.ts:

 export function mapMenusToRoutes(userMenus: any[]) {
  // 1.加载本地路由
  const localRoutes = loadLocalRoutes()

  // 2.根据菜单去匹配正确的路由
  const routes: RouteRecordRaw[] = []
  //这里是只用两层,如果是很多层,就需要用递归。代码稍微复杂一些,这里就不写。主要将动态添加路由的思路
  for (const menu of userMenus) {
    for (const submenu of menu.children) {
      const route = localRoutes.find((item) => item.path === submenu.url)
      if (route) {
        routes.push(route)
      }
    }
  }
  return routes
}

store/login/login.ts:

import { defineStore } from 'pinia'
import {
  accountLoginRequest,
  getUserInfoById,
  getUserMenusByRoleId
} from '@/service/login/login'
import type { IAccount } from '@/types'
import { localCache } from '@/utils/cache'
import { mapMenusToRoutes } from '@/utils/map-menus'
import router from '@/router'
import { LOGIN_TOKEN } from '@/global/constants'

interface ILoginState {
  token: string
  userInfo: any
  userMenus: any
}

const useLoginStore = defineStore('login', {
  // 如何制定state的类型
  state: (): ILoginState => ({
    token: '',
    userInfo: {},
    userMenus: []
  }),
  actions: {
    async loginAccountAction(account: IAccount) {
      // 1.账号登录, 获取token等信息
      const loginResult = await accountLoginRequest(account)
      const id = loginResult.data.id
      this.token = loginResult.data.token
      localCache.setCache(LOGIN_TOKEN, this.token)

      // 2.获取登录用户的详细信息(role信息)
      const userInfoResult = await getUserInfoById(id)
      const userInfo = userInfoResult.data
      this.userInfo = userInfo

      // 3.根据角色请求用户的权限(菜单menus)
      const userMenusResult = await getUserMenusByRoleId(this.userInfo.role.id)
      const userMenus = userMenusResult.data
      this.userMenus = userMenus

      // 4.进行本地缓存
      localCache.setCache('userInfo', userInfo)
      localCache.setCache('userMenus', userMenus)

      // 重要: 动态的添加路由
      const routes = mapMenusToRoutes(userMenus)
      routes.forEach((route) => router.addRoute('main', route))
      // 5.页面跳转(main页面)
      router.push('/main')
    },
  }
})

export default useLoginStore

2.5解决main页面刷新的问题

问题:如果我们重新刷新的话动态路由就会消失,动态路由是在登录成功之后才会调用,刷新的时候并没有调用,所以动态路由没有添加上。
思路:在页面进行刷新的时候,需要初始化动态路由。
初始化动态路由代码如下,store/login/login.ts:

...
const useLoginStore = defineStore('login', {
  // 如何制定state的类型
  state: (): ILoginState => ({
    token: '',
    userInfo: {},
    userMenus: []
  }),
  actions: {
    async loginAccountAction(account: IAccount) {
      ...
      // 重要: 动态的添加路由
      const routes = mapMenusToRoutes(userMenus)
      routes.forEach((route) => router.addRoute('main', route))
      // 5.页面跳转(main页面)
      router.push('/main')
    },
    //初始化动态路由
    loadLocalCacheAction() {
      // 1.用户进行刷新默认加载数据
      const token = localCache.getCache(LOGIN_TOKEN)
      const userInfo = localCache.getCache('userInfo')
      const userMenus = localCache.getCache('userMenus')
      if (token && userInfo && userMenus) {
        this.token = token
        this.userInfo = userInfo
        this.userMenus = userMenus
        // 2.动态添加路由
        const routes = mapMenusToRoutes(userMenus)
        routes.forEach((route) => router.addRoute('main', route))
      }
    }
  }
})
export default useLoginStore

store/index.ts:

import { createPinia } from 'pinia'
import type { App } from 'vue'
import useLoginStore from './login/login'

const pinia = createPinia()
function registerStore(app: App<Element>) {
  // 1.use的pinia
  app.use(pinia)
  // 2.加载本地的数据
  const loginStore = useLoginStore()
  //初始化动态路由
  loginStore.loadLocalCacheAction()
}
export default registerStore

src/main.ts:

import { createApp } from 'vue'
import 'normalize.css'
import './assets/css/index.less'
import App from './App.vue'
import router from './router'
import store from './store'
import icons from './global/register-icons'

const app = createApp(App)
app.use(icons)
app.use(store)
app.use(router)
app.mount('#app')

这样子在页面刷新时候就可以执行“初始化动态路由”的方法了。

2.6解决main的第一个页面匹配显示的问题

改进一下mapMenusToRoutes:

export let firstMenu: any = null
export function mapMenusToRoutes(userMenus: any[]) {
  // 1.加载本地路由
  const localRoutes = loadLocalRoutes()

  // 2.根据菜单去匹配正确的路由
  const routes: RouteRecordRaw[] = []
  for (const menu of userMenus) {
    for (const submenu of menu.children) {
      const route = localRoutes.find((item) => item.path === submenu.url)
      if (route) {
        // 1.给route的顶层菜单增加重定向功能(但是只需要添加一次即可)
        if (!routes.find((item) => item.path === menu.url)) {
          routes.push({ path: menu.url, redirect: route.path })
        }

        // 2.将二级菜单对应的路径
        routes.push(route)
      }
      // 记录第一个被匹配到的菜单
      if (!firstMenu && route) firstMenu = submenu
    }
  }
  return routes
}

在router/index.ts中:

router.beforeEach((to) => {
  // 只有登录成功(token), 才能真正进入到main页面
  const token = localCache.getCache(LOGIN_TOKEN)
  if (to.path.startsWith('/main') && !token) {
    return '/login'
  }

  // 如果是进入到main
  if (to.path === '/main') {
    return firstMenu?.url
  }
})

2.7根据path匹配menu

utils/map-menus.ts:

/**
 * 根据路径去匹配需要显示的菜单
 * @param path 需要匹配的路径
 * @param userMenus 所有的菜单
 */
export function mapPathToMenu(path: string, userMenus: any[]) {
  for (const menu of userMenus) {
    for (const submenu of menu.children) {
      if (submenu.url === path) {
        return submenu
      }
    }
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WPS如何接入DeepSeek(通过JS宏调用)

WPS如何接入DeepSeek 一、文本扩写二、校对三、翻译 本文介绍如何通过 WPS JS宏调用 DeepSeek 大模型&#xff0c;实现自动化文本扩写、校对和翻译等功能。 一、文本扩写 1、随便打开一个word文档&#xff0c;点击工具栏“工具”。 2、点击“开发工具”。 3、点击“查看代码”…

前端快速生成接口方法

大家好&#xff0c;我是苏麟&#xff0c;今天聊一下OpenApi。 官网 &#xff1a; umijs/openapi - npm 安装命令 npm i --save-dev umijs/openapi 在根目录&#xff08;项目目录下&#xff09;创建文件 openapi.config.js import { generateService } from umijs/openapi// 自…

云消息队列 ApsaraMQ Serverless 演进:高弹性低成本、更稳定更安全、智能化免运维

如今&#xff0c;消息队列已成为分布式架构中不可或缺的关键服务&#xff0c;为电商、物联网、游戏和教育等行业&#xff0c;提供了异步解耦、集成、高性能和高可靠的核心价值。 过去一年&#xff0c;我们发布了云消息队列 ApsaraMQ 全系列产品 Serverless 化&#xff0c;面向…

Spring依赖注入方式

写在前面&#xff1a;大家好&#xff01;我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正&#xff0c;感谢大家的不吝赐教。我的唯一博客更新地址是&#xff1a;https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油&#xff0c;冲鸭&#x…

Mysql索引失效的场景

对索引列使用函数或表达式&#xff0c;或参与计算&#xff08;优化方法&#xff1a;将计算移到条件右侧&#xff1a;&#xff09;例 优化 对索引列进行隐式类型转换&#xff0c;条件中的数据类型与索引列的数据类型不匹配&#xff0c;会进行隐式类型转换 以like 通配符开头索…

CTFHub-RCE系列wp

目录标题 引言什么是RCE漏洞 eval执行文件包含文件包含php://input读取源代码远程包含 命令注入无过滤过滤cat过滤空格过滤目录分隔符过滤运算符综合过滤练习 引言 题目共有如下类型 什么是RCE漏洞 RCE漏洞&#xff0c;全称是Remote Code Execution漏洞&#xff0c;翻译成中文…

算法学习笔记之并查集

简介 问题描述&#xff1a;将编号为1-N的N个对象划分为不相交集合&#xff0c;在每个集合中&#xff0c;选择其中的某个元素代表所在集合。 常见两种操作&#xff1a; 1.合并两个集合 2.查找某元素属于哪个集合 实现方法1 用编号最小的元素标记所在集合&#xff1b; 定义…

渗透利器工具:Burp Suite 联动 XRAY 图形化工具.(主动扫描+被动扫描)

Burp Suite 联动 XRAY 图形化工具.&#xff08;主动扫描被动扫描&#xff09; Burp Suite 和 Xray 联合使用&#xff0c;能够将 Burp 的强大流量拦截与修改功能&#xff0c;与 Xray 的高效漏洞检测能力相结合&#xff0c;实现更全面、高效的网络安全测试&#xff0c;同时提升漏…

菌贝:云南鸡枞菌走向世界的第一品牌

云南&#xff0c;这片神奇的土地&#xff0c;孕育了无数珍稀的野生菌&#xff0c;而鸡枞菌无疑是其中的佼佼者。它以其独特的口感和丰富的营养价值&#xff0c;被誉为“菌中之王”。在云南鸡枞菌的品牌化进程中&#xff0c;菌贝以其卓越的品质和广泛的影响力&#xff0c;成为云…

如何恢复使用 Command+Option+Delete 删除的文件:完整指南

在日常使用 Mac 时&#xff0c;我们经常会使用 CommandOptionDelete 组合键来快速删除文件。这种删除方式会将文件直接移出废纸篓&#xff0c;而不会经过废纸篓的中间步骤&#xff0c;因此文件看似被永久删除。然而&#xff0c;即使文件被这样删除&#xff0c;仍然有几种方法可…

windows生成SSL的PFX格式证书

生成crt证书: 安装openssl winget install -e --id FireDaemon.OpenSSL 生成cert openssl req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes -subj "/CN=localhost" 转换pfx openssl pkcs12 -export -out certificate.pfx…

用户认证综合实验

实验需求 需求一&#xff1a;根据下表&#xff0c;完成相关配置 需求二&#xff1a;配置DHCP协议&#xff0c;具体要求如下 需求三&#xff1a;防火墙安全区域配置 需求四&#xff1a;防火墙地址组信息 需求五&#xff1a;管理员 为 FW 配置一个配置管理员。要求管理员可以通…

5.7.2 进度管理

文章目录 进度管理Gantt图PERT图 进度管理 进度安排&#xff1a;通过将项目分解成多个活动&#xff0c;分析活动间的依赖关系&#xff0c;估算工作量&#xff0c;分配资源&#xff0c;制定活动时序。 Gantt图 Gantt图横坐标表示时间&#xff0c;纵坐标表示不同任务。使用一条条…

MQTT(Message Queuing Telemetry Transport)协议(二)

下面为你详细介绍如何基于 TCP 协议对 MQTT 进行封装&#xff0c;包括实现思路、代码示例及代码解释。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h>…

b站——《【强化学习】一小时完全入门》学习笔记及代码(1-3 多臂老虎机)

问题陈述 我们有两个多臂老虎机&#xff08;Multi-Armed Bandit&#xff09;&#xff0c;分别称为左边的老虎机和右边的老虎机。每个老虎机的奖励服从不同的正态分布&#xff1a; 左边的老虎机&#xff1a;奖励服从均值为 500&#xff0c;标准差为 50 的正态分布&#xff0c;即…

Unity 接入Tripo 文生模型,图生模型

官方网站&#xff1a;https://www.tripo3d.ai/app/home自行注册账号并且登陆下载Unity插件&#xff1a;https://cdn-web.tripo3d.ai/plugin/tripo-unity.zip申请apikey&#xff1a; https://platform.tripo3d.ai/api-keys使用&#xff08;后续过程就按照第二步下载的插件里面的…

Arduino 第十一章:温度传感器

Arduino 第十一章&#xff1a;LM35 温度传感器 一、LM35 简介 LM35 是美国国家半导体公司&#xff08;现德州仪器&#xff09;生产的一款精密集成电路温度传感器。与基于热力学原理的传统温度传感器不同&#xff0c;LM35 能直接将温度转换为电压输出&#xff0c;且输出电压与…

【并发控制、更新、版本控制】.NET开源ORM框架 SqlSugar 系列

系列文章目录 &#x1f380;&#x1f380;&#x1f380; .NET开源 ORM 框架 SqlSugar 系列 &#x1f380;&#x1f380;&#x1f380; 文章目录 系列文章目录一、并发累计&#xff08;累加&#xff09;1.1 单条批量累计1.2 批量更新并且字段11.3 批量更新并且字段list中对应的…

5 分钟用满血 DeepSeek R1 搭建个人 AI 知识库(含本地部署)

最近很多朋友都在问&#xff1a;怎么本地部署 DeepSeek 搭建个人知识库。 老实说&#xff0c;如果你不是为了研究技术&#xff0c;或者确实需要保护涉密数据&#xff0c;我真不建议去折腾本地部署。 为什么呢&#xff1f; 目前 Ollama 从 1.5B 到 70B 都只是把 R1 的推理能力…

opc da 服务器数据 转 EtherCAT项目案例

目录 1 案例说明 2 VFBOX网关工作原理 3 应用条件 4 查看OPC DA服务器的相关参数 5 配置网关采集opc da数据 6 启动EtherCAT从站转发采集的数据 7 在服务器上运行仰科OPC DA采集软件 8 案例总结 1 案例说明 在OPC DA服务器上运行OPC DA client软件查看OPC DA服务器的相…