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]) }
})
}
}
其他代码 不是核心的 不贴了
vue 动态菜单以及动态路由加载、刷新采的坑的更多相关文章
- vue-router路由加载两种模式
路由安装npm install --save vue-router 安装完成后,打开package.json,如果看到这个"vue-router": 版本号, 就代表安装成功了 ...
- angularJS 路由加载js controller 未定义 解决方案
说明 本文主要说明,在angularJS框架使用中,angularJS 路由加载js controller 未定义 解决方案. 路由 $routeProvider 异步加载js 路由的基本用法,请查看 ...
- Angular07 路由的工作流程、路由参数、子路由、利用路由加载模块、模块懒加载???
1 Angular路由的工作流程 用户在浏览器输入一个URL -> Angular将获取到这个URL并将其解析成一个UrlTree实例 -> Angular会到路由配置中去寻找并激活与Ur ...
- Flask源码之:路由加载
路由加载整体思路: 1. 将 url = /index 和 methods = [GET,POST] 和 endpoint = "index"封装到Rule对象 2. 将Ru ...
- flask 源码专题(八):路由加载
1.示例代码 from flask import Flask app = Flask(__name__,static_url_path='/xx') @app.route('/index') def ...
- 06 flask源码剖析之路由加载
06 Flask源码之:路由加载 目录 06 Flask源码之:路由加载 1.示例代码 2.路由加载源码分析 1.示例代码 from flask import Flask app = Flask(__ ...
- .net core3.1 abp动态菜单和动态权限(思路) (二)
ps:本文需要先把abp的源码下载一份来下,跟着一起找实现,更容易懂 在abp中,对于权限和菜单使用静态来管理,菜单的加载是在登陆页面的地方(具体是怎么知道的,浏览器按F12,然后去sources中去 ...
- .net core3.1 abp动态菜单和动态权限(动态菜单实现和动态权限添加) (三)
我们来创建动态菜单吧 首先,先对动态菜单的概念.操作.流程进行约束:1.Host和各个Tenant有自己的自定义菜单2.Host和各个Tenant的权限与自定义菜单相关联2.Tenant有一套默认的菜 ...
- vue-cli3.x正确打包项目,解决静态资源与路由加载无效的问题,history模式下配合使用nginx运行打包后的项目
使用vue-cli3.x正确打包项目,配合nginx运行打包后的内容 vue.config.js module.exports = { publicPath: './',//打包后的位置(如果不设置这 ...
随机推荐
- Linux下MySQL主从复制(GTID)+读写分离(ProxySQL)-实施笔记
GTID概念: GTID( Global Transaction Identifier)全局事务标识.GTID 是 5.6 版本引入的一个有关于主从复制的重大改进,相对于之前版本基于 Binlog 文 ...
- SpringBoot博客开发之AOP日志处理
日志处理: 需求分析 日志处理需要记录的是: 请求的URL 访问者IP 调用的方法 传入的参数 返回的内容 上面的内容要求在控制台和日志中输出. 在学习这部分知识的时候,真的感觉收获很多,在之前Spr ...
- BUUCTF-[CISCN2019 华北赛区 Day1 Web5]CyberPunk
BUUCTF-[CISCN2019 华北赛区 Day1 Web5]CyberPunk 看题 看源码有提示?file=? 文件包含漏洞,可以利用这个漏洞读取源码. 分析 index.php?file=p ...
- Docker容器管理——Docker容器常用命令
1.查看所有的容器 docker ps 2.查看运行的容器 docker ps -a 3.启动.停止.重启docker容器 docker start ... docker stop ... docke ...
- client-go实战之五:DiscoveryClient
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 痞子衡嵌入式:MCUXpresso IDE下将关键函数重定向到RAM中执行的几种方法
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是MCUXpresso IDE下将关键函数重定向到RAM中执行的几种方法. 前段时间痞子衡写了一篇 <在IAR开发环境下将关键函数重 ...
- Hamcrest 断言框架
Hamcrest是一个为了测试为目的,能组合成灵活表达式的匹配器类库.用于编断言的框架,使用这个框架编写断言,提高可读性及开发测试的效率,提供了大量"匹配器"方法,每个匹配器用于执 ...
- python 直接插入排序
# 先将未排序的元素放到九天之上,一个临时变量temp,上到九天之上去观察前面已经排好的序列, # 然后从后向前对比,只要临时变量小于某个位置的值,就将其向前移动一位,就是给比它下标大 # 1的位置处 ...
- find用法 以及和exec xargs 的组合使用
1.查找当前目录下所有的txt的文件 [root@master1 ~]# find . -name "*.txt" -type f ./a.txt ./b.txt 2.exec 结 ...
- 队列,一种"公平"的数据结构
路过一家奶茶店,由于生意火爆,门口的排着长长的队伍,先排队的人先买到奶茶,然后再轮到下一个,秩序井然.有没有一种数据结构能体现"先来后到"这种顺序呢? 当然有,那就是队列.先看一下 ...