您现在的位置是:首页 >技术交流 >vue3+ts 动态路由网站首页技术交流

vue3+ts 动态路由

别惊醒渔人 2025-02-19 12:01:03
简介vue3 ts 动态路由

一.关于动态路由与静态路由

 动态路由和静态路由是网络中常用的两种路由配置方式,它们在工作原理、适用场景、优缺点等方面存在诸多不同,以下是详细的对比:

工作原理

  • 静态路由:由网络管理员手动配置,指定到达特定网络或主机的路径。它不会自动调整,除非管理员手动修改配置。例如,管理员在路由器上明确指定,当数据包要去往某个特定网络时,应该通过某个特定的接口和下一跳地址。

  • 动态路由:通过路由协议(如RIP、OSPF、BGP等)自动学习和更新路由信息。路由器之间会定期交换路由信息,根据网络拓扑的变化自动计算最优路径。例如,当网络中的链路状态发生变化时,动态路由协议会自动感知并重新计算路由,更新路由表。

配置复杂度

  • 静态路由:配置相对简单,只需指定目标网络、子网掩码和下一跳地址或出接口即可。适合小型网络或对路由配置要求不复杂的场景。

  • 动态路由:配置相对复杂,需要配置路由协议、相关参数(如认证、路由优先级等),并且需要对路由协议的原理和工作机制有较深入的了解。不过,一旦配置完成,它可以自动适应网络拓扑的变化。

路由表更新方式

  • 静态路由:路由表不会自动更新,除非管理员手动修改。因此,当网络拓扑发生变化时,需要人工干预来更新路由表。

  • 动态路由:路由表会根据路由协议的算法自动更新。例如,当链路中断或恢复时,动态路由协议会通过更新消息通知其他路由器,从而更新路由表。

适用场景

  • 静态路由:适用于小型网络、网络拓扑结构简单且稳定的情况,例如小型企业网络或单个局域网。在这种场景下,手动配置路由相对容易且高效。

  • 动态路由:适用于大型网络、网络拓扑结构复杂且经常变化的情况,例如互联网服务提供商(ISP)的骨干网络或大型企业网络。动态路由能够自动适应网络变化,减少人工维护工作量。

路由的设置各式各样,接下来我将分享最近学到的一种方法

二.结构管理

建立基础管理结构

将页面路由单独抽取出来写成文件进行管理,此时router.index.ts 只放一些共有的页面路由

dashboard.ts的内容如下

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

这时我们就会感觉非常麻烦,如果增加一个页面就要手动增加一个路由文件,麻烦又费时

这时候不得不提到一个插件了

下载插件   coderwhy

执行口令:

 npm install coderwhy -g

创建文件

在项目文件夹根目录下执行口令

add3:表示vue3

department:表示所创建的文件名

-d:目标地址

回车之后,router文件夹下会自动创建相关文件夹,并已经完成路由书写,同时 我们创建的department.vue 文件也已经填写了基础的代码块

coderwhy add3page_setup departmenet -d src/views/system/department

我们应该在什么时候完成动态路由的加载?

登录完成时,我们应当根据后端给我们返回的用户信息判断用户身份,并加载完成对应的路由

登录时,我们通常会在pinia 中 管理我们的用户信息。于是我决定自登录的pinia 拿到返回的用户信息后顺便添加相关路由

  localCache.setCache:我封装的一个小组件,用来进行本地缓存

utils下新建map-menus .ts
import type { RouteRecordRaw } from 'vue-router'

function loadLocalRoutes() {
  // 1.动态获取所有的路由对象, 放到数组中
  // * 路由对象都在独立的文件中
  // * 从文件中将所有路由对象先读取数组中
  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
}

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
}

 在LoginStore中使用map-menus .ts,拿到返回值后遍历添加路由

import { defineStore } from 'pinia'
import {
  accountLoginRequest,
  getUserInfoById,
  getUserMenusByRoleId
} from '@/service/login/login'
import { mapMenusToRoutes } from '@/utils/map-menus'

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')
    },

    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
        // 3.动态添加路由
        const routes = mapMenusToRoutes(userMenus)
        routes.forEach((route) => router.addRoute('main', route))
      }
    }
  }
})

export default useLoginStore

欢迎各位大佬指正

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。