Vue动态路由实现逻辑

meta: {

1、登录后跳转的授权页redierect.vue,获取动态路由的数组,存储于store.ts

vue动态路由权限 vue动态路由实现权限控制vue动态路由权限 vue动态路由实现权限控制


vue动态路由权限 vue动态路由实现权限控制


label: '用户组设置',

2、在main.ts 中引用路由守卫文件

3、在permission.ts中用到了

导航前置守卫,在调用路由之前会先调用该方法,在该方法中通过store.ts的路由数组动态渲染路由后访问。

4、在asyncRouter.js通过定义 getAsyncRoutes 进行路由数组的格式化,同时此处也可以用来通过接口获取路由信息,但是我就不查了,太浪费资源。

permission.name: 'Describe',ts内容如下

如何优雅地在vue中添加权限控制示例详解

摁我刷新页面

前言 在一个项目中,一些功能会涉及到重要的数据管理,为了确保数据的安全,我们会在项目中加入权限来限制每个用户的作。作为前端,我们要做的是配合后端给到的权限数据,做页面上的各种各样的限制。

{path: 'group',

需求 因为这是一个工作上的业务需求,所以对于我来说主要有两个地方需要进行权限控制。

个是侧边菜单栏,需要控制显示与隐藏。 第二个就是页面内的各个按钮,弹窗等。

流程

1、如何获取用户权限? 后端(当前用户拥有的权限列表)-> 前端(通过后端的接口获取到,下文中我们把当前用户的权限列表叫做 permissionList)

2、前端如何做限制? 通过产品的需求,在项目中进行权限点的配置,然后通过 permissionList 寻找是否有配置的权限点,有就显示,没有就不显示。

3、然后呢? 没了。

当我刚开始接到这个需求的时候就是这么想的,这有什么难的,不就获取 permissionList 然后判断就可以了嘛。后来我才发现真正的需求远比我想象的复杂。 真正的问题

上面的需求有提到我们主要解决两个问题,侧边菜单栏的显示 & 页面内作。 设我们有这样一个路由的设置(以下只是一个例子):

import VueRouter from 'vue-router'

/ 注意:以下配置仅为部分配置,并且省去了 component 的配置 /

export const routes = [

{path: '/',

name: 'Admin',

label: '首页'

{path: '/user',

name: 'User',

label: '用户',

redirect: { name: 'UserList' },

children: [

name: 'UserList',

label: '用户列表'

na}})me: 'UserGroup',

label: '用户组',

redirect: { name: 'UserGroupList' },

children: [

name: 'UserGroupList',

label: '用户组列表'

{path: 'config',

name: 'UserGroupConfig',

label: '用户组设置'

}]

}]

label: '系统设置'

{path: '/login',

name: 'Login',

label: '登录'

}]

const router = new VueRouter({

routes

export default router

其中前两级路由会显示在侧边栏中,第就不会显示在侧边栏中了。 页面内作的权限设置不需要考虑很多其他东西,我们主要针对侧边栏以及路由进行问题的分析,通过分析,主要有以下几个问题:

什么时候获取 permissionList,如何存储 permissionList

子路由全都没权限时不应该显示本身(例:当用户列表和用户组都没有权限时,用户也不应该显示在侧边栏)

默认重定向的路由没有权限时,应寻找 children 中有权限的一项重定向(例:用户路由重定向到用户列表路由,若用户列表没有权限,则应该重定向到用户组路由)

当用户直接输入没有权限的 时需要跳转到没有权限的页面或其他作。(路由限制)

下面我们针对以上问题一个一个解决。 什么时候获取权限,存储在哪 & 路由限制

我这里是在 router 的 beforeEach 中获取的,获取的 permissionList 是存放在 vuex 中。 原因是考虑到要做路由的限制,以及方便后面项目中对权限列表的使用,以下是实现的示例:

首先我们加入权限配置到 router 上: // 以下只展示部分配置

{path: '/user',

name: 'User',

label: '用户',

permissions: ['U_1']

redirect: { name: 'UserList' },

children: [

name: 'UserList',

label: '用户列表',

permissions: ['U_1_1']

name: 'UserGroup',

label: '用户组',

permissions: ['U_1_2']

redirect: { name: 'UserGroupList' },

children: [

name: 'UserGroupList',

label: '用户组列表',

permissions: ['U_1_2_1']

{path: 'config',

name: 'UserGroupConfig',

permissions: ['U_1_2_2']

}}

]}

]}

可以看到我们把权限加在了 meta 上,是为了更简单的从 router.beforeEch 中进行权限判断,权限设置为一个数组,是因为一个页面可能涉及多个权限。 接下来我们设置 router.beforeEach :

// 引入项目的 vuex

import store from '@/store'

// 引入判断是否拥有权限的函数

import { includePermission } from '@/utils/permission'

router.beforeEach(async (to, from, next) => {

// 先判断是否为登录,登录了才能获取到权限,怎么判断登录就不写了

if (!isLogin) {

try {

// 这里获取 permissionList

await store.dispatch('getPermissionList')

// 这里判断当前页面是否有权限

const { permissions } = (permissions) {

const hasPermission = includePermission(permissions)

if (!hasPermission) next({ name: 'NoPermission' })

}next()

}} else {

next({ name: 'Login' })

我们可以看到我们需要一个判断权限的方法 & vuex 中的 getPermissionList 如下: // @/store

export default {

state: {

permissionList: []

mutations: {

updatePermissionList: (state, payload) => {

state.permissionList = payload

actions: {

getPermissionList: async ({ state, commit }) => {

// 这里是为了防止重复获取

if (state.permissionList.length) return

// 发送请求方法省略

const list = await api.getPermissionList()

commit('updatePermissionList', list)

}}

}// @/utils/permission

import store from '@/store'

判断是否拥有权限

@param {Array} permissions - 要判断的权限列表

/

function includePermission (permissions = []) {

// 这里要判断的权限没有设置的话,就等于不需要权限,直接返回 true

if (!permissions.length) return true

const permissionList = store.state.permissionList

return !!permissions.find(permission => permissionList.includes(permission))

}重定向问题 以上我们解决了路由的基本配置与权限如何获取,怎么限制路由跳转,接下来我们要处理的就是重定向问题了。

这一点可能和我们项目本身架构有关,我们项目的侧边栏下还有子级,是以下图中的 tab 切换展现的,正常情况当点击品管理后页面会重定向到入库管理的 tab 切换页面,但当入库管理没有权限时,则应该直接重定向到出库管理界面。 所以想实现以上的效果,我需要重写 router 的 redirect,做到可以动态判断(因为在我配置路由时并不知道当前用户的权限列表)

然后我查看了 vue-router 的文档,发现了 redirect 可以是一个方法,这样就可以解决重定向问题了。 vue-router 中 redirect 说明 ,根据说明我们可以改写 redirect 如下:

// 我们需要引入判断权限方法

import { includePermission } from '@/utils/permission'

const children = [

name: 'UserList',

label: '用户列表',

permissions: ['U_1_1']

name: 'UserGroup',

label: '用户组',

permissions: ['U_1_2']

}}

]const routeDemo = {

path: '/user',

name: 'User',

label: '用户',

redirect: (to) => {

if return { name: children[0].name }

if return { name: children[1].name }

children

}虽然问题解决了,但是发现这样写下去很麻烦,还要修改 router 的配置,所以我们使用一个方法生成: // @/utils/permission

创建重定向函数

@param {Object} redirect - 重定向对象

@param {Array} children - 子列表

/

function createRedirectFn (redirect = {}, children = []) {

// 避免缓存太大,只保留 children 的 name 和 permissions

const permissionChildren = children.map(({ name = '', meta: { permissions = [] } = {} }) => ({ name, permissions }))

return function (to) {

// 这里一定不能在 return 的函数外面筛选,因为权限是异步获取的

const hasPermissionChildren = permissionChildren.filter( => includePermission(.permissions))

const defaultName = redirect.name || ''

// 如果默认重定向没有权限,则从 children 中选择个有权限的路由做重定向

const firstPermissionName = (hasPermissionChildren[0] || { name: '' }).name

// 判断是否需要修改默认的重定向

const seDefaultName = !!hasPermissionChildren.find( => .name === defaultName && defaultName)

if (seDefaultName) return { name: defaultName }

else return firstPermissionName ? { name: firstPermissionName } : redirect

}}

然后我们就可以改写为: // 我们需要引入判断权限方法

import { includePermission, createRedirectFn } from '@/utils/permission'

const children = [

name: 'UserList',

label: '用户列表',

permissions: ['U_1_1']

name: 'UserGroup',

label: '用户组',

permissions: ['U_1_2']

}}

]const routeDemo = {

path: '/user',

name: 'User',

label: '用户',

redirect: createRedirectFn({ name: 'UserList' }, children),

children

}这样稍微简洁一些,但我还是需要一个一个路由去修改,所以我又写了一个方法来递归 router 配置,并重写他们的 redirect: // @/utils/permission

创建有权限的路由配置(多级)

@param {Object} config - 路由配置对象

@param {Object} config.redirect - 必须是 children 中的一个,并且使用 name

/

function createPermissionRouter ({ redirect, children = [], ...others }) {

const needRecursion = !!children.length

if (needRecursion) {

return {

redirect: createRedirectFn(redirect, children),

children: children.map( => createPermissionRouter())

}} else {

return {

redirect

}}

}这样我们只需要在最外层的 router 配置加上这样一层函数就可以了: import { createPermissionRouter } from '@/utils/permission'

const routesConfig = [

{path: '/user',

name: 'User',

label: '用户',

permissions: ['U_1']

redirect: { name: 'UserList' },

children: [

name: 'UserList',

label: '用户列表',

permissions: ['U_1_1']

name: 'UserGroup',

label: '用户组',

permissions: ['U_1_2']

redirect: { name: 'UserGroupList' },

children: [

name: 'UserGroupList',

label: '用户组列表',

permissions: ['U_1_2_1']

{path: 'config',

name: 'UserGroupConfig',

permissions: ['U_1_2_2']

}}

]}

]}

]export const routes = routesConfig.map( => createPermissionRouter())

const router = new VueRouter({

routes

export default router

当然这样写还有一个好处,其实你并不需要设置 redirect,这样会自动重定向到 children 的个有权限的路由 侧边栏显示问题

我们的项目使用的是根据路由的配置来生成侧边栏的,当然会加一些其他的参数来显示显示层级等问题,这里就不写具体代码了,如何解决侧边栏 children 全都无权限不显示的问题呢。 这里我的思路是,把路由的配置也一同更新到 vuex 中,然后侧边栏配置从 vuex 中的配置来读取。

由于这个地方涉及修改的东西有点多,而且涉及业务,我就不把代码拿出来了,你可以自行实验。 方便团队部署权限点的方法

以上我们解决了大部分权限的问题,那么还有很多涉及到业务逻辑的权限点的部署,所以为了团队中其他人可以优雅简单的部署权限点到各个页面中,我在项目中提供了以下几种方式来部署权限:

{hasPermission () {

// 通过方法 $permission 判断是否拥有权限

return this.$permission(['U_1_1', 'U_1_2'])

}}

这里要注意,为了 $permission 方法的返回值是可被监测的,判断时需要从 this.$sto

vue菜单权限刷新后才可见

@param {string} redirect.name - 重定向的组件名称

可以会卡顿。每个路由都需要进行匹配和解析,而多层嵌套的路由将导致匹配时间变长,从而影响应用程序的性能。我们在登录页面模拟获取数据之后,我们通过菜单的一个方法进行生成菜单,通过路由的方法生成路由数组并进行循环添加,然后执行路由跳转。。

根据查询相关息显示,vue初始化路由组件先定义出来,处理后台返回的路由数据。

vue是一份完整的菜单数据,通过后台返回角色的菜单列表两者对比,筛选需要显示的菜单数据绑定。

vue路由配置name和path是什么作用

通过全局方法 this.$permission 判断,因为有些权限并非在模版中的

name,path。

1、name:路由的名称const route},_data = JSON . parse ( sessionStorage . getItem ( "route_data" )); //获取路由信息,用于在跳转路由时进行识别。通过给每个路由配置一个的名称,可以方便地在代码中使用路由名称来进行跳转,而不必硬编码具体的路径。

2、path:路由的路径,用于指定该路由对应的URL地址。当用户访问匹配该路径的URL时,Vuejs会将其路由到对应的组件。

vue-router中,父级路由不能有name属性

可以

vue项目中,使用了vue-router,我的场景是在一个路由中嵌套了子级路由,然后我在运行项目的时候,给出了:

{path: '/forget' , //访问

源码为:

原来是在vue-router中,当路由有嵌套的子级路由的时候,父级路由需要一个默认的路由,不能再给其}},设置name属性了,我们只需要将父级路由的name属性去掉就可以了;

vueios左滑不触发生命周期

当前页面:实例演示

使用了第三方库,路由配置问题,页面滚动问题。

1、使用了第三方库:某些第{path: '/setting',三方库会影响vuerouter的生命周期钩子函数,确保没有使用任何干扰vuerouter生命周期的库。

2、路由配置问题:检查路由配置是否正确,确保在每个路由组件中都正确地设置了生命周期钩子函数,例如created、mounted等。

3、页面滚动问题:某些移动端浏览器在左滑页面时会滚动页面,这会影响生命周期的执行,可以添加datanoscroll等于true属性到body标签,以禁止页面滚动。

vue-router4层级多了,会卡顿

//for ( let index = 0 ; index < route_data . length ; index ++) { //生成路由信息 默认填写的重定向的 name

1、懒加载路由:使用懒加载路由可以在需要时异步加载组件并分块打包,从而避免一次性加载所有组件,优化页面加载速度。

2、合理划分路由:根...others,据业务需求合理划分路由,避免无限制的添加子路由,尤其是对于大型项目而言。

3、缓存组件:对于那些不经常发生变化的组件,应该启用缓存策略以避免重复渲染。

4、使用动态路由:如果你需要创建许多相似的路由,则可以使用动态路由。动态路由可以根据参数生成路由。

前端vue开发 路由元信息可以改变吗

通过指令 v-permission 来直接在 template 上设置

(1)路由定义

const router = new VueRouter({

routes: [

component: Foo,

meta: { requiresAuth: true }// a meta field

}]

这里的

meta 字段就是路由元信息字段,requiresAuth 是自己起的字段名称,用来标记这个路由信息是否需要检测,true 表示要检测,false

表示不需要检测(这个名称随便起,比如我自己的就起的 requiresId,或者你懒得想,就直接 a ,b 这么起,当然,还是比较建议起个有意义的名称)

代码

new Vue({

el: '#app',

router,

template: '',

components: { App },

render: h}) => h(App),

created () {

this.redrct()

mods: {

redrct () {

router.beforeEach((to, from, next) => {

if (to.matched.some(record => { //这里meta字段的名称要与上面route里面保持一致

// this route requires Id, check if logged in

// if not, redirect to login page.

if (!this.loggedIn()) { // 自己的判断条件next() // 确保一定要调用 next()

next({

path: '/', // 重定向后的路由

query: { redirect: to.fullPath } // 登录成功之后可以根据query中的内容跳转回原来的路由(页面)

} else {

next()

}} else {

loggedIn () {

var id = sessionStorage.getItem('userId')

if (id === null) { // 未登录

return false

}return true // 别忘了这句啊,之前忘写了,调了好半天呢

}}

vue-router 路由守卫

(2)js

一.全局守卫

1.全局前置守卫

语法:我们通过动态路由的形式,我们生成的菜单权限更加的完善,不仅实现依靠菜单与路由守卫拦截实现鉴权,也可以通过动态路由实现动态加载vue文件,控制更加深度

参数说明:

to :进入到哪个路由去

from :从哪个路由离开

next :函数,决定是否展示你要看到的路由页面。

{path: 'list',示例:

main.js 中设置全局守卫

2.全局后置守卫

语法:

参数说明:

二.组件内守卫

1.到达组件时

语法:

说明:

进行访问admin页面,会发现alert输出hello undefined。这是因为,现在访问不到我们的data属性,执行顺序是不一致,这与的声明周期有关。在执行完之前,data数据还未渲染。所以这里,next()会给一个对应的回调,帮助完成。

2.离开组件时

语法:

说明:

三.路由独享守卫

语法:

说明:

vue项目实现动态路由和动态菜单搭建插件式开发框架免费源码

})

以往我们在开发vue项目的时候,总是通过将路径和路由写在route/index.js文件中,然后直接进行访问即可,一般实现权限匹配都是通过菜单下面的权限参数和路由守卫进行一个验证拦截和权限匹配,然而这样安全性仍然不足。因为我们在route/index.js中已经写满了所有的路由,这样子不仅造成静态路由内容过多、修改困难,同时当静态路由内容过多的时候,我们在路由中的内容就显得极其复杂。

activated 和 deactivated 和我们之前学习的生命周期函数一样,也是组件的生命周期函数。不过, activated 和 deactivated 只在 内的所有嵌套组件中触发。 activated :进入组件时触发。 deactivated :退出组件时触发。

而后端对前端的控制也显得较为无力,无法实现严格性的控制。

由此我们发现通过动态路由控制是必然的,此时我们只需要通过后端获取数据菜单和路由信息json,然后动态添加路由并生成菜单,使菜单与动态路由内容进行一个匹配,这样子我们可以实现由后端控制前端的菜单和路由,我们的项目往往只需要内置几个组件无需权限的公共页面如登陆、注册、忘记密码和404错误这几个常用页面组件。

我们只需要将写好的组件放置到我们的view视图下,然后我们通过动态的路由和菜单实现路由添加和菜单进行匹配,我们便可实现对插件进行访问,我们减少了对route/index.js内容写入,同时也有利于减少内存的占用。

我们通过动态路由的形式,我们可以将项目分给不同的人进行完成,便于组建一个开发团队,因为他们所开发的组件,我们只需要在具备基本的jascript库的情况下。我们直接进行动态路由的一个挂载和菜单生成便可完成项目合作,减少了对route/index.js文件的作,保证项目的完整性。

我发现在非node环境的开发条件下,我们可以实现远程的vue文件加载,这不仅为我们开发提供了便利,同时也有利于我们及时修改文件,以达到项目的需求,更有利于保障安全,实现vue文件加载。

Vue:2.6.11。

Vue-route:3.2.0。

主页

聊天

第二怎样对动态路由和菜单项目进行一个管理。

我们首先可以通过搭建一个组件通过添加路由信息和管理菜单实现二者的动态匹配。我们只需要对路由信息进行一个添加和修改,并和菜单相互间进行匹配,我们便可实现简单的路由挂载。

组件管理

菜单管理

此时将数据提交的后端由后端进行数据保存,我们此时的组件只需要放在views文件夹下,添加路由进行文件加载,我们便可实现路由管理。

登陆页面配置。

我们需要在静态文件夹下创建一个menu.json和route.json。两个json文件模拟登录时返回的数据。

第二配置路由初始化内容。我们将route/index.js的路由信息填为空是非常不理智的,而且会报错,因为路由初始化在加载前已经完成。有些页面完全不需要权限便可访问,比如登录、注册、找回密码和404错误,这种不需要权限的页面,我们还是需要将其直接以静态的形式写在route/index.js文件中。

Index初始数据

import Vue from 'vue'

import VueRouter from 'vue-router'

Vue . use ( VueRouter )

const routes = [{

path: '/' , //访问

name: 'login' , //路由名称

component : () => import ( '@/unitui/pages/Login.vue' ), //加载模板文件

show_site: 0 , //是否全屏显示

web_title: "登录" //网站标题

{path: '/register' , //访问

name: 'register' , //路由名称

component : () => import ( '@/unitui/pages/Register.vue' ), //加载模板文件

show_site: 0 , //是否全屏显示

web_title: "注册" //网站标题

name: 'forget' , //路由名称

component : () => import ( '@/unitui/pages/Forget.vue' ), //加载模板文件

show_site: 0 , //是否全屏显示

web_title: "找回密码" //网站标题

{path: '/404' , //访问

name: '404' , //路由名称

component : () => import ( '@/unitui/pages/404.vue' ), //加载模板文件

show_site: 0 , //是否全屏显示

web_title: "404错误" //网站标题

]const router = new VueRouter ({

routes

router . beforeEach (( to , from , next ) => {

document . title = to . meta . web_title

console . log ( to );

next ()

export default router

第三,关于防止刷新后丢失的问题。我们需要在app.vue文件中的mods方法中定义一个路由生成方法。

示例:

init_route () { //初始化路由,防止刷新丢失

if ( sessionStorage . getItem ( "route_data" ) != null ) { //只有后端已经返回数据的情况下才允许生成

const data = []; //默认路由数组

data [ index ] = {

path: route_data [ index ]. path , //访问

name: route_data [ index ]. name , //路由名称

component : resolve =>

require ([ `@/views/ ${ route_data [ index ]. component } ` ], resolve ), //加载模板文件

show_site: route_data [ index ]. meta . show_site , //是否全屏显示

web_title: route_data [ index ]. meta . web_title //网站标题

}};

}for ( let index = 0 ; index < data . length ; index ++) { //循环添加路由

this . $router . addRoute ( data [ index ]);

}}

}在mounted中进行方法调用,防止刷新的时路由丢失,导致发生错误。该方法内容基本和登陆页面的菜单出路由初始内容基本相同,但我们别的是,我们需要判断登陆所获取的路由信息是否存在,只有在存在的时候及后端已经返回了路由信息,即证明登录成功的时候,我们才会动态添加路由。

在刷新之后,默认跳转到path:’’的一个路由界面中去,此时我们解决方法只需要将path:’’路由进行一个删除,将其删除就变可正常访问。

第二动态路由跳转时发生Cann{path: '/foo',ot find module xxx错误。

意思是无法加载我们指定的一个vue文件,这是由于route3.0版本后import方式不支持传入变量,此时我们只需要将其改为require方式便可。

我们此次动态vue项目开发已经基本完成,我的开发的项目是基于element-ui进行,那么如果你需要源码参考。可以私信回复unit便可获取。