当前位置: 首页 > 编程日记 > 正文

Vue 增加动态路由功能 【在原有系统上增加】

目录

遇到问题

1. 修改router/index.js

2. 修改 store文件夹下的

2.1 增加 modules/permission.js

2.2 增加modules/tagsViews.js

2.3 修改modules/user.js

2.4 修改getter.js

2.5 修改index.js

遇到问题

1.当出现循环刷新页面,不断进行请求时,检查配置的动态菜单 权限是否配置正确;切换身份导致菜单不发生变化;

2. Duplicate named routes definition [菜单配置不对]

由于我的配置的菜单下 只有一个菜单,我是将【1】 里的 roles配置 加到 【2】 上导致 登陆时封装菜单错误,不断刷新页面,登陆成功后切换身份也导致菜单显示不对。

3.问题描述 配置好动态路由后,在动态路由的路径刷新页面报 ,第一次点击是好的,一旦刷新页面出以下问题

Error in beforeCreate hook: "RangeError: Maximum call stack size exceeded"

RangeError: Maximum call stack size exceeded

Error in render: "TypeError: Cannot read properties of undefined (reading 'matched')"

Vue-router-3.0.1 使用router.addRoutes()设置动态路由,页面刷新后无效 - #25 by BruceChoo7 - 中文 - Vue Forumicon-default.png?t=M276https://forum.vuejs.org/t/vue-router-3-0-1-router-addroutes/33181/25

解决办法

初始路由不要加重定向到404路由,否则beforeEach时地址已经变成/404了,将 404 添加到动态地址中

1. 修改router/index.js

增加

export const asyncRoutes = [{path: '/qw',component: Layout,name: 'qw',meta: { title: '企微微信', icon: 'el-icon-files',roles: ['admin', 'dev']  },children: [{path: 'msg',name: 'msg',component:  () => import('@/views/qw/msg'),meta: { title: '企微消息素材管理', icon: 'el-icon-document'}}]}
]

2. 修改 store文件夹下的

2.1 增加 modules/permission.js

import { asyncRoutes, constantRoutes } from '@/router'/*** Use meta.role to determine if the current user has permission* @param roles* @param route*/
function hasPermission(roles, route) {if (route.meta && route.meta.roles) {return roles.some(role => route.meta.roles.includes(role))} else {return true}
}/*** Filter asynchronous routing tables by recursion* @param routes asyncRoutes* @param roles*/
export function filterAsyncRoutes(routes, roles) {const res = []routes.forEach(route => {const tmp = { ...route }if (hasPermission(roles, tmp)) {if (tmp.children) {tmp.children = filterAsyncRoutes(tmp.children, roles)}res.push(tmp)}})return res
}const state = {routes: [],addRoutes: []
}const mutations = {SET_ROUTES: (state, routes) => {state.addRoutes = routesstate.routes = constantRoutes.concat(routes)}
}const actions = {generateRoutes({ commit }, roles) {return new Promise(resolve => {let accessedRoutesif (roles.includes('admin')) {accessedRoutes = asyncRoutes || []} else {accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)}commit('SET_ROUTES', accessedRoutes)resolve(accessedRoutes)})}
}export default {namespaced: true,state,mutations,actions
}

2.2 增加modules/tagsViews.js

const state = {visitedViews: [],cachedViews: []
}const mutations = {ADD_VISITED_VIEW: (state, view) => {if (state.visitedViews.some(v => v.path === view.path)) returnstate.visitedViews.push(Object.assign({}, view, {title: view.meta.title || 'no-name'}))},ADD_CACHED_VIEW: (state, view) => {if (state.cachedViews.includes(view.name)) returnif (!view.meta.noCache) {state.cachedViews.push(view.name)}},DEL_VISITED_VIEW: (state, view) => {for (const [i, v] of state.visitedViews.entries()) {if (v.path === view.path) {state.visitedViews.splice(i, 1)break}}},DEL_CACHED_VIEW: (state, view) => {const index = state.cachedViews.indexOf(view.name)index > -1 && state.cachedViews.splice(index, 1)},DEL_OTHERS_VISITED_VIEWS: (state, view) => {state.visitedViews = state.visitedViews.filter(v => {return v.meta.affix || v.path === view.path})},DEL_OTHERS_CACHED_VIEWS: (state, view) => {const index = state.cachedViews.indexOf(view.name)if (index > -1) {state.cachedViews = state.cachedViews.slice(index, index + 1)} else {// if index = -1, there is no cached tagsstate.cachedViews = []}},DEL_ALL_VISITED_VIEWS: state => {// keep affix tagsconst affixTags = state.visitedViews.filter(tag => tag.meta.affix)state.visitedViews = affixTags},DEL_ALL_CACHED_VIEWS: state => {state.cachedViews = []},UPDATE_VISITED_VIEW: (state, view) => {for (let v of state.visitedViews) {if (v.path === view.path) {v = Object.assign(v, view)break}}}
}const actions = {addView({ dispatch }, view) {dispatch('addVisitedView', view)dispatch('addCachedView', view)},addVisitedView({ commit }, view) {commit('ADD_VISITED_VIEW', view)},addCachedView({ commit }, view) {commit('ADD_CACHED_VIEW', view)},delView({ dispatch, state }, view) {return new Promise(resolve => {dispatch('delVisitedView', view)dispatch('delCachedView', view)resolve({visitedViews: [...state.visitedViews],cachedViews: [...state.cachedViews]})})},delVisitedView({ commit, state }, view) {return new Promise(resolve => {commit('DEL_VISITED_VIEW', view)resolve([...state.visitedViews])})},delCachedView({ commit, state }, view) {return new Promise(resolve => {commit('DEL_CACHED_VIEW', view)resolve([...state.cachedViews])})},delOthersViews({ dispatch, state }, view) {return new Promise(resolve => {dispatch('delOthersVisitedViews', view)dispatch('delOthersCachedViews', view)resolve({visitedViews: [...state.visitedViews],cachedViews: [...state.cachedViews]})})},delOthersVisitedViews({ commit, state }, view) {return new Promise(resolve => {commit('DEL_OTHERS_VISITED_VIEWS', view)resolve([...state.visitedViews])})},delOthersCachedViews({ commit, state }, view) {return new Promise(resolve => {commit('DEL_OTHERS_CACHED_VIEWS', view)resolve([...state.cachedViews])})},delAllViews({ dispatch, state }, view) {return new Promise(resolve => {dispatch('delAllVisitedViews', view)dispatch('delAllCachedViews', view)resolve({visitedViews: [...state.visitedViews],cachedViews: [...state.cachedViews]})})},delAllVisitedViews({ commit, state }) {return new Promise(resolve => {commit('DEL_ALL_VISITED_VIEWS')resolve([...state.visitedViews])})},delAllCachedViews({ commit, state }) {return new Promise(resolve => {commit('DEL_ALL_CACHED_VIEWS')resolve([...state.cachedViews])})},updateVisitedView({ commit }, view) {commit('UPDATE_VISITED_VIEW', view)}
}export default {namespaced: true,state,mutations,actions
}

2.3 修改modules/user.js

import { login, logout, getInfo } from '@/api/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import router,{ resetRouter } from '@/router'const getDefaultState = () => {return {token: getToken(),name: '',group:'',roles:'',avatar: ''}
}const state = getDefaultState()const mutations = {RESET_STATE: (state) => {Object.assign(state, getDefaultState())},SET_TOKEN: (state, token) => {state.token = token},SET_NAME: (state, name) => {state.name = name},SET_GROUP: (state, group) => {state.group = group},SET_ROLES: (state, roles) => {state.roles = roles},SET_AVATAR: (state, avatar) => {state.avatar = avatar}
}const actions = {// user loginlogin({ commit }, userInfo) {const { username, password } = userInforeturn new Promise((resolve, reject) => {login({ username: username.trim(), password: password }).then(response => {const { data } = responsecommit('SET_TOKEN', data.token)// commit('SET_NAME', data.username)// commit('SET_GROUP', data.group)// commit('SET_ROLES', data.role)setToken(data.token)resolve()}).catch(error => {reject(error)})})},// get user infogetInfo({ commit, state }) {return new Promise((resolve, reject) => {getInfo(state.token).then(response => {console.log(response)const { data } = responseif (!data) {reject('Verification failed, please Login again.')}console.log(data)const { username, avatar,group,roles } = datacommit('SET_NAME', username)commit('SET_AVATAR', avatar)commit('SET_GROUP', group)commit('SET_ROLES', roles)resolve(data)}).catch(error => {reject(error)})})},// user logoutlogout({ commit, state }) {return new Promise((resolve, reject) => {removeToken() // must remove  token  firstresetRouter()commit('RESET_STATE')resolve()// logout(state.token).then(() => {//   removeToken() // must remove  token  first//   resetRouter()//   commit('RESET_STATE')//   resolve()// }).catch(error => {//   reject(error)// })})},// remove tokenresetToken({ commit }) {return new Promise(resolve => {removeToken() // must remove  token  firstcommit('RESET_STATE')resolve()})},// dynamically modify permissionsasync changeRoles({ commit, dispatch }, role) {const token = role + '-token'commit('SET_TOKEN', token)setToken(token)const { roles } = await dispatch('getInfo')resetRouter()// generate accessible routes map based on rolesconst accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })// dynamically add accessible routesrouter.addRoutes(accessRoutes)// reset visited views and cached viewsdispatch('tagsView/delAllViews', null, { root: true })}
}export default {namespaced: true,state,mutations,actions
}

2.4 修改getter.js

const getters = {sidebar: state => state.app.sidebar,device: state => state.app.device,token: state => state.user.token,avatar: state => state.user.avatar,name: state => state.user.name,roles: state => state.user.roles,permission_routers: state => state.permission.routes,
}
export default getters

2.5 修改index.js

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'Vue.use(Vuex)// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {// set './app.js' => 'app'const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')const value = modulesFiles(modulePath)modules[moduleName] = value.defaultreturn modules
}, {})const store = new Vuex.Store({modules,getters
})export default store

2.3 修改permission.js

主要修改红框中的

import router from "./router";
import store from "./store";
import { Message } from "element-ui";
import NProgress from "nprogress"; // progress bar
import "nprogress/nprogress.css"; // progress bar style
import { getToken } from "@/utils/auth"; // get token from cookie
import getPageTitle from "@/utils/get-page-title";NProgress.configure({ showSpinner: false }); // NProgress Configurationconst whiteList = ["/login", "/funnelAnalyse", "/retentionAnalyse"]; // no redirect whitelistrouter.beforeEach(async (to, from, next) => {// start progress barNProgress.start();// set page titledocument.title = getPageTitle(to.meta.title);// determine whether the user has logged inconst hasToken = getToken();if (hasToken) {if (to.path === "/login") {// if is logged in, redirect to the home pagenext({ path: "/" });NProgress.done();} else {const hasRoles = store.getters.roles && store.getters.roles.length > 0if (hasRoles) {next();} else {try {// get user info// await store.dispatch("user/getInfo");// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']const { roles } = await store.dispatch('user/getInfo')// generate accessible routes map based on rolesconst accessRoutes = await store.dispatch('permission/generateRoutes', roles)// dynamically add accessible routesrouter.addRoutes(accessRoutes)// hack method to ensure that addRoutes is complete// set the replace: true, so the navigation will not leave a history recordnext({ ...to, replace: true })// next();} catch (error) {// remove token and go to login page to re-login// await store.dispatch("user/resetToken");await store.dispatch('user/resetToken')Message.error('Has Error')next(`/login?redirect=${to.path}`)NProgress.done()}}}} else {/* has no token*/if (whiteList.indexOf(to.path) !== -1) {// in the free login whitelist, go directlynext();} else {// other pages that do not have permission to access are redirected to the login page.next(`/login?redirect=${to.path}`);NProgress.done();}}
});router.afterEach(() => {// finish progress barNProgress.done();
});

参考

vue-admin-template 添加权限控制路由功能_fiskeryang的专栏-CSDN博客vue-element-template添加权限控制路由功能vue-element-template添加权限控制路由功能1、 变更@/router/index.js2、添加@/store/modules/permission.js3、改造数据库与实体4、@/store/modules/user.js5、更新 getter.js 和 index.js6、变更 @/permission.jsvue-element-template添加权限控制路由功能vue-element-template 是没有实现路由权https://blog.csdn.net/fiskeryang/article/details/112358889

相关文章:

读取 android的内存、cpu、流量等 信息

内存总量:/proc/meminfocpu信息:/proc/cpuinfocpu使用率:/proc/stat流量信息:/proc/self/net/dev /proc/net/devetc/network/interfaces 这个文件是保存ip,netmask,gateway信息的(包括静态和动态)&#xff…

CCNA基础知识汇总

本资源是本人学习的过程中的一些笔记和学习中用到的文档。主要包括ospf,ppp,ACL与策略路由,帧中继,***方面。希望能对大家CCNA的学习有所帮助。下载地址:http://down.51cto.com/data/128047 转载于:https://blog.51cto…

PHP面试内容 整理搜集 PHP面试涉及技术 一文回顾全部 主要含PHP面试命令列表 方法列表...

PHP面试时常涉及的内容总结 熟悉框架 逻辑题 快排 正则 数组函数....抽奖, 秒杀数据库 优化,sql书写缓存 redis mecacheLinux命令其他技术 sphinx, swool 异步处理,(同步异步 分布式)其他语言 Java python(多线程 爬虫) go c(一般温个别的)PHP7新特性 整理制作 https://www.cn…

Python 文件 close() 方法

描述 Python 文件 close() 方法用于关闭一个已打开的文件。关闭后的文件不能再进行读写操作, 否则会触发 ValueError 错误。 close() 方法允许调用多次。 当 file 对象,被引用到操作另外一个文件时,Python 会自动关闭之前的 file 对象。 使用…

校园音乐点歌平台的设计与开发 微信小程序 推荐点歌 java 开发

1、 微信小程序前台展示 (基于协同过滤算法 根据用户点歌行为 对用户点歌进行推荐) 2 、 使用到的技术框架 Springbootmavenmybatis网易云相关API 3、 后台展示 项目地址: 项目地址

Code Reading -chap4

Chapter4: C Data Structures 67. Read explicit data structure operations in terms of the underlying abstract data class.(P96) 依据显式数据结构背后的抽象数据类去阅读该显式数据结构操作。 -----&#xf…

在Red Hat Linux5下构建LAMP网站服务平台之MySQL、PHP的安装与配置

在Red Hat Linux5下构建LAMP网站服务平台之MySQL、PHP的安装与配置 2010-09-09 16:40:49标签:PHP Linux mysql RedHat    [推送到技术圈] 版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和…

移动端iPhone系列适配问题的一些坑

完成移动端的开发项目之后,发现谷歌自带的调试器似乎没有什么太大的作用,整天借同事的苹果手机测bug,尽管同事不厌其烦,但还是觉得这iPhone系列适配问题适配到想逃逃逃,好在项目已经顺利完成,测试通过,下面…

shred命令

不做陈冠希必备。。。。 shred --help 用法:shred [选项]... 文件... Overwrite the specified FILE(s) repeatedly, in order to make it harder for even very expensive hardware probing to recover the data.Mandatory arguments to long options are mandator…

WPF初探--RichTextBox

1. 设置RichTextBox运行换行 将AcceptReturn属性设置为true 2. 保存RichTextBox内容到文件 //path为完整保存路径名 private void SaveRtfFile(string path) { FileStream fs new FileStream(path, FileMode.Create); TextRange range; range new TextRange(your…

手把手视频第一节

个人的总结: 今天又重新开始看一套单片机视频,算上这一套已经是第三套了,也总结了一些教训。首先是在抄代码的时候不明白的地方就算后来明白了也要加注释,解释这句话的意思,否则以后看的时候一定是一脸懵逼。 手把手第…

异步操作(三)

APM的轮询聚焦技巧 就从字面意思来理解,每隔一段时间来查询,异步操作的结果。而怎么实现轮询的方法了,这里就要谈到IAsyncResult接口。它定义了若干个只读属性 publicinterfaceIAsyncResult{ Object AsyncState {get;} WaitHandle AsyncWaitH…

Django-C002-深入模型,到底有多深

此文章完成度【100%】留着以后忘记的回顾。多写多练多思考,我会努力写出有意思的demo,如果知识点有错误、误导,欢迎大家在评论处写下你的感想或者纠错。 ORM介绍:对象关系映射(英语:(Object Relational Map…

Linux中断流程分析

裸机中断: 1、中断流入口 2、事先注册中断处理程序 3、根据中断源编号,调取处理程序 irq_svc:1、等到产生中断源的编号(每一个中断号都有一个描述结构) 2、转载于:https://www.cnblogs.com/sanshijvshi/p/8531025.html…

手把手视频第二节

一、单片机的三大内部资源(我们作为用户,单片机可以提供给我们的资源) 1、FALSH(程序存储空间) (1)早期使用的一般是TOPROM ,程序只能写入一次,程序写错了只能换一块。 &…

SQL Server DATEADD() 函数

定义和用法 DATEADD() 函数在日期中添加或减去指定的时间间隔。 语法 DATEADD(datepart,number,date) date 参数是合法的日期表达式。number 是您希望添加的间隔数;对于未来的时间,此数是正数,对于过去的时间,此数是负数。 datepa…

致广大关注《网络规划设计师考试案例梳理、真题透解与强化训练》读者朋友的一封信...

致广大关注《网络规划设计师考试案例梳理、真题透解与强化训练》读者朋友的一封信 书是人类进步的阶梯,读书是增强个人软实力的佳径。好读书是你的美德,读好书是你的选择,书好读是我们的承诺!如果有心,不妨把一卷《网络…

Mac MySQL 数据库配置(关系型数据库管理系统)

本文已停止更新,点击此链接查看本文最新内容 !!!前言 MySQL 关系型数据库管理系统。1、配置准备工作 1)配置数据库准备工作 下载相关软件 mysql-5.7.21-1-macos10.13-x86_64.dmgmysql-workbench-community-6.3.10-maco…

SSM框架——Spring+SpringMVC+Mybatis的搭建教程

一:概述SSM框架在项目开发中经常使用到,相比于SSH框架,它在仅几年的开发中运用的更加广泛。 Spring作为一个轻量级的框架,有很多的拓展功能,最主要的我们一般项目使用的就是IOC和AOP。SpringMVC是Spring实现的一个Web层…

【java】兴唐课程第五节到第九节知识点总结

第九节 1、 代码:void readBook(String… bookNames) 表示不确定参数的个数,此时变量为一个数组。 2、当方法中的参数名称(如stuname)和属性名称相同时。 this.stuname表示属性 stuname表示参数。 3、主方法与所在的累无关,是一个程序的入口…

构建RHEL上的extmail

一、extmail_solutionz 1、ExtMail Solution 结构 ExtMail Solution 是一个基于优秀开源软件的电子邮件系统解决方案,核心部件包括了Postfix、Amavisd-new、ClamAV、ExtMail、ExtMan、Courier系列软件。是一个功能相对比较齐全的免费电子邮件系统。以下是其主要的特…

MapReduce_wordcount

测试数据: [hadooph201 mapreduce]$ more counttext.txt hello mamahello babahello wordcai wen weimama baba jiejie gegegege jiejie didimeimei jiejiedidi mamaayi shushuayi mamahello mamahello babahello wordcai wen weimama baba jiejie gegegege jiejie …

Appium+python自动化(八)- 初识琵琶女Appium(千呼万唤始出来,犹抱琵琶半遮面)- 下(超详解)...

​简介 通过上一篇宏哥给各位小伙伴们的引荐,大家移动对这位美女有了深刻的认识,而且她那高超的技艺和婀娜的身姿久久地浮现在你的脑海里,是不是这样呢???不要害羞直接告诉宏哥:是,就…

蜻蜓resin服务器虚拟目录的设置

首先&#xff0c;别急着打开服务器先&#xff0c;接住打开resin主目录下的conf文件夹的resin.conf文件&#xff0c;老规矩&#xff0c;备份先&#xff0c;mv resin.conf resin.conf.bak然后vi resin.conf 文件&#xff0c;找到如下这段代码&#xff1a;1 <!--configures the…

【java】兴唐第十节课知识点总结

1、使用main里的成员方法也要实例化对象吗&#xff1f; 必须实例化 ///重点&#xff01; 2、在成员方法中调用另一个成员方法可以直接调用&#xff08;前面省略一个this.&#xff09; 3、 \n也可以在java里用 4、null可以是除了基本数据类型外的任何数据类型 5、基本数据类…

SharePoint2010是个什么东西

Microsoft SharePoint Foundation is an application that is built on top of Internet Information Services (IIS) and the Microsoft ASP.NET Framework. Microsoft SharePoint Foundation 是架构在IIS和ASP.NET Framework上的一个应用程序。IIS是与互联网站点相关的&#…

Linux Shell高级技巧(目录)

为了方便我们每个人的学习&#xff0c;这里将给出Linux Shell高级技巧五篇系列博客的目录以供大家在需要时参阅和查找。 Linux Shell高级技巧(一) http://www.cnblogs.com/stephen-liu74/archive/2011/12/22/2271167.html一、将输入信息转换为大写字符后再进行条件判断二、为调…

Keras卷积+池化层学习

转自&#xff1a;https://keras-cn.readthedocs.io/en/latest/layers/convolutional_layer/ https://keras-cn.readthedocs.io/en/latest/layers/pooling_layer/ 1.con1D keras.layers.convolutional.Conv1D(filters, kernel_size, strides1, paddingvalid, dilation_rate1, ac…

【Java】阿里巴巴java开发手册总结(我能看懂的)

尽管这本《手册》句句是精华&#xff0c;但由于我还是个菜鸟&#xff0c;这里仅作&#xff08;我能用的到的&&我能看懂的&#xff09;的笔记 1.1命名风格 1、类名用UpperCamelCase的风格 2、方法名、参数名、成员变量、局部变量都统一用lowerCameCase的风格&#xff…

关于maya与max互导FBX出现错误的解决方案。

因为自己实在是不愿意一次又一次把时间浪费在导入导出的问题上。每一次都是多试几次才成功&#xff0c;也没有真正去测试这个东西。但是今天实在是碰到了错误中的极品了。最后还是决定写下来。。算是给自己做笔记吧。。大家如果在导入导出的时候遇到一些问题不妨试试以下几种方…