权限控制与布局组件的实现
最近在学习vue-element-admin时,重点研究了权限控制与布局组件的结合实现。
侧边栏组件(Sidebar)
项目中使用了基于Element UI的NavMenu实现侧边栏。核心组件包括:
- index.vue:负责初始化菜单结构
- SidebarItem.vue:处理路由的递归渲染
- Link.vue:处理链接跳转逻辑
侧边栏初始化
在index.vue中,主要实现如下:
<template>
<div class="sidebar-container">
<el-scrollbar>
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
mode="vertical"
>
<menu-item
v-for="route in routes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
</el-menu>
</el-scrollbar>
</div>
</template>
<script>
import MenuItems from './SidebarItem'
export default {
components: {
MenuItems
},
computed: {
activeMenu() {
return this.$route.path
},
routes() {
return this.$store.state.routes
},
isCollapse() {
return this.$store.state.isCollapse
}
}
}
</script>
菜单项渲染
SidebarItem.vue通过递归方式渲染菜单结构:
<template>
<div v-if="!item.hidden">
<template v-if="hasOneChild(item.children) && !item.alwaysShow">
<app-link :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)">
<item :icon="onlyOneChild.icon" :title="onlyOneChild.title" />
</el-menu-item>
</app-link>
</template>
<el-submenu v-else :index="resolvePath(item.path)">
<template slot="title">
<item :icon="item.icon" :title="item.title" />
</template>
<menu-item
v-for="child in item.children"
:key="child.path"
:item="child"
:base-path="resolvePath(child.path)"
/>
</el-submenu>
</div>
</template>
<script>
import path from 'path'
import Item from './Item'
import AppLink from './Link'
export default {
name: 'MenuItem',
components: { Item, AppLink },
props: {
item: {
type: Object,
required: true
},
basePath: {
type: String,
default: ''
}
},
data() {
this.onlyOneChild = null
return {}
},
methods: {
hasOneChild(children = []) {
const showingChildren = children.filter(item => !item.hidden)
if (showingChildren.length === 1) {
this.onlyOneChild = showingChildren[0]
return true
}
return false
},
resolvePath(routePath) {
return path.resolve(this.basePath, routePath)
}
}
}
</script>
权限加载问题
在测试中发现首次登录后菜单未加载的问题,经过排查发现是由于权限逻辑的初始化顺序问题。通过调整登录流程中的权限处理代码,问题得以解决。
submitlogin({ commit }, payload) {
const { username, password } = payload
return new Promise((resolve, reject) => {
login(username.trim(), password)
.then(response => {
if (response.data.token != "error") {
commit('SET_TOKEN', response.data.token)
commit('SET_NAME', response.data.name)
setToken(response.data.token)
resolve()
router.push('/')
} else {
console.log(response.data.token)
resolve()
router.push('/404')
}
})
.catch(error => {
reject(error)
})
})
}