中小型企业网站建设,东营网站建设制作,网站建设 提升和扩大,wordpress 微博客前言
在 【Vue框架】Vue路由配置 中的getters.js里#xff0c;可以看到有一个应用程序的状态#xff08;变量#xff09;叫 permission_routes#xff0c;这个就是管理前端菜单栏的状态。具体代码的介绍#xff0c;都以注释的形式来说明。
1、modules\permission.js
1…前言
在 【Vue框架】Vue路由配置 中的getters.js里可以看到有一个应用程序的状态变量叫 permission_routes这个就是管理前端菜单栏的状态。具体代码的介绍都以注释的形式来说明。
1、modules\permission.js
1.1 代码
import { asyncRoutes, constantRoutes } from /router/*** Use meta.role to determine if the current user has permission* param roles 用户角色* param route 路由信息*/
function hasPermission(roles, route) {// 判断route是否存在meta和meta.rolesif (route.meta route.meta.roles) {// 判断当前传入的角色是否存在路由的route中return roles.some(role route.meta.roles.includes(role))} else {return true}
}/*** Filter asynchronous routing tables by recursion* 通过 递归 筛选异步路由表* 【将 基础路由不含角色权限和 符合用户权限的动态路由需要角色权限全部存入res】* param routes asyncRoutes【去看router\index.js中asyncRoutes】* param roles*/
export function filterAsyncRoutes(routes, roles) {const res []// routes是在router\index.js定义的路由数组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)) { // 如果roles数组中包含adminaccessedRoutes asyncRoutes || [] // 动态路由全部可以访问如果asyncRoutes为undefined或null则取[]} else {accessedRoutes filterAsyncRoutes(asyncRoutes, roles) // 递归出符合条件的路由}commit(SET_ROUTES, accessedRoutes)resolve(accessedRoutes)})}
}
// 默认导出一个对象包含了模块的相关配置
export default {// 设置模块的命名空间为 true这意味着该模块中的状态、mutations、getters、actions将被封装在命名空间中以避免和其他模块的冲突namespaced: true,// 模块的状态state,// 模块的变化方法mutations,// 模块的行为方法调用action触发mutations改变stateactions
}
该文件除了定义的routes路由状态和addRoutes动态添加的路由后续用到的时候在提主要在actions中定义了生成路由的行为方法generateRoutes根据roles角色和内置传入的{ commit }context.commit获取router\index.js中定义的一系列路由简单说就是在前端页面上被访问的路径。
补充防忘记
new Promise()以及其参数【Vue框架】Vue路由配置 看看路由【Vue框架】Vuex状态管理
1.2 想法
在modules\permission.js中根据generateRoutes提前写好的逻辑来判断查回用户的权限是否符合这样不利于添加新角色的改动。 应该都得从数据库中查询得到库中的角色和每个动态路由。个人猜想后续在尝试
2、layout\components\Sidebar
2.1 index.vue
遍历展示整体的菜单栏。
templatediv :class{has-logo:showLogo}logo v-ifshowLogo :collapseisCollapse /el-scrollbar wrap-classscrollbar-wrapperel-menu:default-activeactiveMenu:collapseisCollapse:background-colorvariables.menuBg:text-colorvariables.menuText:unique-openedfalse:active-text-colorvariables.menuActiveText:collapse-transitionfalsemodeverticalsidebar-item v-forroute in permission_routes :keyroute.path :itemroute :base-pathroute.path //el-menu/el-scrollbar/div
/templatescript
import { mapGetters } from vuex // 从vuex库中导入mapGetters函数用于将getter映射到该组件的计算属性中
import Logo from ./Logo
import SidebarItem from ./SidebarItem
import variables from /styles/variables.scssexport default {// 在该组件中注册了SidebarItem和Logo两个组件以便在模板中使用它们components: { SidebarItem, Logo },// computed计算属性中可以定义一些依赖于其他数据的属性。这些属性的值会根据其依赖的数据动态计算得出并在依赖数据发生变化时自动更新。// computed计算属性的定义方式可以是一个对象对象的每个属性都是一个计算属性的定义// ...mapGetters([...])将mapGetters返回的映射对象展开并添加到该组件的计算属性中这样可以直接访问映射的getter// mapGetters([...])里的数组中包含想要映射的getter方法的名称computed: {...mapGetters([permission_routes,sidebar]),// 根据当前路由对象的元信息meta中的activeMenu属性来确定活动的菜单项。// 如果未设置activeMenu属性则返回当前路径pathactiveMenu() {const route this.$route // this.$route是在Vue中访问当前路由的对象(全局属性只读不能直接更改路由信息)const { meta, path } route// if set path, the sidebar will highlight the path you setif (meta.activeMenu) {return meta.activeMenu // 侧边栏将高亮显示设置的路径}return path // 如果未设置activeMenu属性则返回当前路由的路径。侧边栏将根据当前路径高亮显示相应的菜单项},showLogo() {return this.$store.state.settings.sidebarLogo},variables() {return variables},isCollapse() {// 如果opened属性为true则isCollapse为false表示侧边栏未折叠// 如果opened属性为false则isCollapse为true表示侧边栏已折叠return !this.sidebar.opened}}
}
/script2.2 SidebarItem.vue
具体遍历显示每一个具体的菜单项。
templatediv v-if!item.hidden classmenu-wrapper!-- 这的item就是routeonlyOneChild就是当前route下的子菜单 --!-- 1判断route下是否为0或1个子菜单 2(!当前route下的子菜单是还存在子菜单||子菜单不存在时) 3--!-- 这里的template当前route下只有1个或0个子菜单且唯一子菜单下不存在下级菜单时执行这段代码效果菜单栏中该route为一级菜单不显示其子菜单--template v-ifhasOneShowingChild(item.children,item) (!onlyOneChild.children||onlyOneChild.noShowingChildren)!item.alwaysShow!-- 其子菜单中存在meta --app-link v-ifonlyOneChild.meta :toresolvePath(onlyOneChild.path)el-menu-item :indexresolvePath(onlyOneChild.path) :class{submenu-title-noDropdown:!isNest}item :icononlyOneChild.meta.icon||(item.metaitem.meta.icon) :titleonlyOneChild.meta.title //el-menu-item/app-link/template!-- 存在多级子菜单的时候 --el-submenu v-else refsubMenu :indexresolvePath(item.path) popper-append-to-body!-- 这里的插槽名为title作用和上面一样主要是显示一级菜单但这里没用app-link让该菜单具有跳转功能 --template slottitleitem v-ifitem.meta :iconitem.meta item.meta.icon :titleitem.meta.title //template!-- 具体的菜单项遍历各个子菜单 --sidebar-itemv-forchild in item.children:keychild.path:is-nesttrue:itemchild:base-pathresolvePath(child.path)classnest-menu//el-submenu/div
/templatescript
import path from path
import { isExternal } from /utils/validate
import Item from ./Item
import AppLink from ./Link
import FixiOSBug from ./FixiOSBugexport default {name: SidebarItem,components: { Item, AppLink },// 通过 mixins 可以将一些常用的选项如 data、methods、created 等或复杂逻辑封装成可复用的模块并在多个组件中混入使用mixins: [FixiOSBug],// 用于定义组件的属性。可以是数组、对象或具体的属性定义。通过 props 可以接收组件外部传入的数据并在组件内部使用props: {// route objectitem: {type: Object,required: true},isNest: {type: Boolean,default: false},basePath: {type: String,default: }},data() {// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237// TODO: refactor with render function// 当前route的子菜单this.onlyOneChild nullreturn {}},methods: {hasOneShowingChild(children [], parent) {const showingChildren children.filter(item {if (item.hidden) {return false} else {// Temp set(will be used if only has one showing child)this.onlyOneChild itemreturn true}})// 只存在一个子菜单// When there is only one child router, the child router is displayed by defaultif (showingChildren.length 1) {return true}// 不存在菜单// Show parent if there are no child router to displayif (showingChildren.length 0) {// 如果没有子菜单显示将父级菜单的一些属性复制到onlyOneChild对象中同时设置onlyOneChild的path为空字符串// 并设置noShowingChildren属性为true表示没有子菜单显示。最后返回true。this.onlyOneChild { ... parent, path: , noShowingChildren: true }return true}// 子菜单存在多个的时候return false},resolvePath(routePath) {// isExternal(routePath)函数判断routePath是否为外部链接如果是外部链接则直接返回routePath不做处理// 当只有唯一子菜单时routePath是子菜单路径if (isExternal(routePath)) {return routePath}// 当只有唯一子菜单时basePath是父级菜单的路径if (isExternal(this.basePath)) {return this.basePath}// path.resolve()函数将this.basePath和routePath拼接成一个完整的路径并返回该路径// 返回 /父级菜单的路径/子菜单路径return path.resolve(this.basePath, routePath)}}
}
/script2.3 Link.vue
template!-- eslint-disable vue/require-component-is --component v-bindlinkProps(to)slot //component
/templatescript
import { isExternal } from /utils/validateexport default {props: {to: {type: String,required: true}},methods: {linkProps(url) {if (isExternal(url)) {return {is: a, // 标签名href: url, // 链接target: _blank, // 用于指定链接在哪个窗口或框架中打开,_blank在新的标签页中打开链接rel: noopener // 用于指定链接与当前页面之间的关系,当使用target_blank时防止新打开的窗口通过window.opener属性访问到当前页面的信息提高安全性。}}return {is: router-link, // 标签名to: url}}}
}
/script