vue动态菜单、动态路由加载以及刷新踩坑实战

作者:创业男生 时间:2024-05-05 09:25:27 

需求:

从接口动态获取子菜单数据 动态加载 要求只有展开才加载子菜单数据 支持刷新,页面显示正常

vue动态菜单、动态路由加载以及刷新踩坑实战

思路:

一开始比较乱,思路很多。想了很多

首先路由和菜单共用一个全局route, 数据的传递也是通过store的route, 然后要考虑的俩个点就是一个就是渲染菜单和加载路由,可以在导航首位里处理路由,处理刷新。

还有一个地方就是菜单组件里展开事件里面 重新生成菜单数据,路由。大体思路差不多,做完就忘了..... 刷新的问题需要用本地缓存处理,之前一直缓存这个route 大数据,但是这个localstore 缓存的只是字符串,不能缓存对象,这样的话,菜单是出来了,动态的路由404,因为json.parse 转出来的对象 不是真实路由数据,还需要单独处理component 这个是个函数对象,
都是坑....所以之前走了点弯路,思路没想好。

第二天,重新整理思路,想了下,为啥要缓存整个route对象,傻是不是,动态的数据只是一部分, * 菜单...何不分开存储,本地存储动态菜单数据,利用完整的路由模板,取出来的初始化路由对象,然后,循环菜单数据,动态设置children属性,生成一个新的完整的路由对象,addRoute不是更好吗
想到这里,整理下完整思路

【定义全局route对象】=> 【导航首位判断刷新、初始化加载 store中route为空】=> 【初始化路由和菜单】=> 【菜单展开事件里面,请求接口,拿到子菜单数据,localStore 存储菜单数据,更新路由】
还有一些小坑 比如重复路由、刷新404问题、刷新白屏、异步处理...

教训:

问题肯定能解决,折腾几天,最后才发现思路最重要

思路错误,就是浪费时间

先想好思路,完整的实现路线 先干什么后干什么 其中遇到技术难点再去百度

分享正文:

暴力贴代码!!!!!!!!!!!!!

全局定义store route对象 都会,忽略


import Vue from 'vue'
import Router from 'vue-router'
import Layout from '@/layout'

Vue.use(Router)

export const constantRoutes = [{
 path: '/login',
 name: 'login',
 component: () => import('@/views/login/index'),
 hidden: true,
}, {
 path: '/404',
 name: '404',
 component: () => import('@/views/error-page/404'),
 hidden: true
}, {
 path: '/401',
 name: '401',
 component: () => import('@/views/error-page/401'),
 hidden: true
}, {
 path: '/',
 component: Layout,
 redirect: '/dashboard',
 children: [
   {
     path: 'dashboard',
     component: () => import('@/views/dashboard/index'),
     name: 'dashboard',
     meta: { title: '首页', icon: 'documentation' }
   },
   {
     path: 'xxx',
     component: () => import('xxxxx'),
     name: 'xxx',
     meta: { title: 'XXX', icon: 'component' },
     children: [
         {
           path: 'host',
           name: 'host',
           meta: {
             title: 'xxx',
             key: 'host'
           }
         },
         {
           path: 'control',
           name: 'control',
           alwaysShow: true,
           meta: {
             title: 'xxx',
             key: 'control'
           },
           children: []
         },
         {
           path: 'signal',
           name: 'signal',
           alwaysShow: true,
           meta: {
             title: 'xxx',
             key: 'signal',
           },
           children: []
         },
         {
           path: 'gateway',
           name: 'gateway',
           alwaysShow: true,
           meta: {
             title: 'xxx',
             key: 'gateway'
           },
           children: []
         }
     ]
   },
   {
     path: 'meeting',
     name: 'meting',
     meta: { title: 'xxx', icon: 'list' }
   },
   {
     path: 'traces',
     component: () => import('@/views/xxx'),
     name: 'traces',
     meta: { title: 'xxx', icon: 'chart' }
   }
]
},
 {
   path: '*',
   redirect: '/404',
   hidden: true
 }
]

const router = new Router({
 // mode: 'history', // require service support
 scrollBehavior: () => ({
   y: 0
 }),
 //routes: constantRoutes 守卫初始化,这里注释掉
})

//路由重复的问题 解决
router.$addRoutes = (params) => {
 router.matcher = new Router({ // 重置路由规则
   scrollBehavior: () => ({
     y: 0
   })
 }).matcher
 router.addRoutes(params) // 添加路由
}

export default router

//监听路由守卫 生成动态路由
router.beforeEach((to, from, next) => {

const routes = store.state.app.routes

console.error('beforeEach 守卫执行了')

//处理首次加载 刷新
 if(routes.length === 0){
    console.error('首次/刷新了')

//更新路由缓存
    const cacheRoute = getLocalRouteInfo()

const routeValue = asyncRouteDataToRoute(cacheRoute.asyncRouteData, constantRoutes)

store
     .dispatch('app/setRoutes', routeValue)

router.$addRoutes([...routeValue])

next({
       ...to,
       replace: true
    })
    return
  }

next()
})

/**
* 更新 * 子菜单 路由元数据
*/
export const updateIPChildRoutes = function(routes, path, children) {
   return setRouteArrayChildren(routes, path, children)
}

/**
* 根据父菜单加载子菜单
* @param {*} routeKey
* @returns
*/
export const generateIPChildRoutes =  function(routeKey) {
   return new Promise((resolve, reject) => {
     if (!routeKey) return

// const start = getDateSeconds(new Date())
     // const end = setDateSeconds(new Date(), 15, 'm')

const filterAddr = grafanaAddrs.filter(addr => addr.key === routeKey)[0]
     const matchup = filterAddr.matchup

const params = {
       matchup
     }

//动态添加routers
     try {
       fetchIPInstance(params).then(ipAddrs => {
         const ipRoutes = []
         ipAddrs.forEach(
           addr => {
               const ipInstance = addr.instance.replace(/^(.*):.*$/, "$1")

if(!isIPAddress(ipInstance))
                 return

const existRoute = ipRoutes.find(ip => ip.meta && ip.meta.key === ipInstance)

!existRoute && ipRoutes.push(
                 {
                   path: ipInstance,
                   name: ipInstance,
                   meta: {
                       title: ipInstance,
                       key: ipInstance
                   }
                 }
               )
           }
         )
         resolve(ipRoutes)
       })
     } catch (error) {
       reject(error)
       console.error(`加载子菜单错误`)
     }
   })
}

import { isArray, setRouteArrayChildren } from './tool'

// 设置路由缓存值
const localRouteKey = "LOCALROUTESET";

/**
* currentPath: '' //当前访问的路由路径
* routeData: [], //存储的完整路由数据(仅加载菜单可用)
* asyncRouteData: [] //动态的路由数据(生成新路由使用)
* {
*    parentKey //父级key
*    route: [
*      {
           path: ,
           name: ,
           meta: {
               title: ,
               key:
           }
       }
*    ]
* }
*/

export function getLocalRouteInfo() {
 const data = localStorage.getItem(localRouteKey);

return data ? JSON.parse(data) : {};
}

export function setLocalRouteInfo(data) {
 const localData = getLocalRouteInfo();

localStorage.setItem(
   localRouteKey,
   JSON.stringify({
     ...localData,
     ...data,
   })
 );
}

export function removeLocalRouteInfo() {
 localStorage.removeItem(localRouteKey);
}

/**
* 本地缓存 转化成路由元数据
* @param {*} constantRoutes 路由模板
*/
export function asyncRouteDataToRoute(asyncRouteData, constantRoutes) {
  let route = constantRoutes
  if (isArray(asyncRouteData) && asyncRouteData.length > 0) {
    asyncRouteData.forEach(
       data => {
         route = setRouteArrayChildren(route, data.parentKey, data.route)
       }
    )
  }
  return route
}

/**
* 设置路由children属性
* @param {*} routes
* @param {*} path
* @param {*} children
* @returns
*/
export const setRouteArrayChildren = function(routes, path, children) {

if (!isArray(routes) || !path)
    return new Array()

for (const route of routes) {
   if (isArray(route.children)) {
     if (route.path === path && route.children.length === 0) {
       route.children.push(...children)
     } else {
       setRouteArrayChildren(route.children, path, children)
     }
   }
 }

return routes
}

onExpandMenu(key, keyPath) {
     console.error(key, keyPath)

const path = key.substring(key.lastIndexOf('/') + 1)
     console.error(path)

//动态生成监控 * 菜单/路由
     const ipAddrKeys = []
     grafanaAddrs.forEach(
       addr => {
         if (addr.matchup) {
           ipAddrKeys.push(addr.key)
         }
       }
     )

if (path && ipAddrKeys.includes(path)) {

generateIPChildRoutes(path)
        .then(ipAddrs => {

if (isArray(ipAddrs)) {

//缓存动态路由数据
           const localRouteInfo = getLocalRouteInfo()
           const cacheRoutes = localRouteInfo.asyncRouteData || []
           cacheRoutes.push(
               {
                   parentKey: path,
                   route: ipAddrs
               }
             )
           setLocalRouteInfo({
             asyncRouteData : cacheRoutes
           })

//更新route
           let asyncRoutes = store.state.app.routes

asyncRoutes = updateIPChildRoutes(asyncRoutes, path, ipAddrs)

store
             .dispatch('app/setRoutes', asyncRoutes)

router.$addRoutes([...asyncRoutes])

}
        })
     }
   }

其他代码 不是核心的 不贴了

来源:https://www.cnblogs.com/sybboy/p/15412322.html

标签:vue,动态菜单,动态路由
0
投稿

猜你喜欢

  • Python之Pygame的Draw绘图

    2022-11-29 18:51:18
  • Golang实现http server提供压缩文件下载功能

    2024-05-09 14:56:00
  • 个人经验总结:完全卸载MySQL数据库5.0

    2009-01-04 13:07:00
  • js string 转 int 注意的问题小结

    2024-05-03 15:30:04
  • 用Python获取亚马逊商品信息

    2021-11-22 12:29:04
  • 一篇文章弄懂PHP和HTML的嵌套写法

    2023-06-20 04:51:22
  • asp随机生成文件名的函数

    2009-02-11 13:41:00
  • Pycharm 字体大小调整设置的方法实现

    2023-10-23 19:35:11
  • php使用curl抓取qq空间的访客信息示例

    2023-10-30 05:50:32
  • MYSQL删除匿名用户的方法(提高安全性)

    2024-01-26 23:04:48
  • JavaScript开发人员的10个关键习惯小结

    2024-04-18 09:51:09
  • python中将字典转换成其json字符串

    2023-10-16 23:46:41
  • 详解MySQL数据类型int(M)中M的含义

    2024-01-14 03:07:05
  • Python DataFrame使用drop_duplicates()函数去重(保留重复值,取重复值)

    2023-09-29 20:42:35
  • mysql基础架构教程之查询语句执行的流程详解

    2024-01-28 21:05:47
  • ASP FCKeditor在线编辑器使用方法

    2023-01-12 23:15:04
  • 用 AjaxTags 简化 Ajax 开发

    2007-11-27 00:00:00
  • 记录密码的asp代码

    2009-11-02 10:50:00
  • SQL Server 作业同步 (结合备份作业)

    2012-07-11 15:59:47
  • MySQL数据库优化之索引实现原理与用法分析

    2024-01-27 08:12:37
  • asp之家 网络编程 m.aspxhome.com