应用场景:
一般管理端的菜单栏是根据登录用户角色不同,动态生成的,在vue中我们不止菜单栏需要动态生成,同时我们路由也需要动态生成。
使用到的组件:
组件名称 | 组件版本 | 组件作用 |
---|---|---|
axios | 1.3.4 | 用于发送请求获取数据 |
element-ui | 2.15.13 | 前端ui组件库,制作页面使用 |
vue-router | 3.5.1 | vue路由组件 |
vuex | 3.6.2 | 路由状态管理 |
mockjs | 1.1.0 | 模拟后台返回数据接口 |
代码实现:
项目结构:
axios相关代码
http.js
代码语言:javascript复制import axios from 'axios'
import router from '@/router/index.js'
import ElementUI from 'element-ui'
const request = axios.create({
// baseURL: 'http://192.168.1.150:8888/'
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
})
request.interceptors.response.use(config => {
const code = config.data.code
if (code === 200) {
return config
} else {
ElementUI.Message('服务忙')
return Promise.reject
}
}, error => {
switch (error.response.status) {
case 404:
router.push('/404')
break
case 500:
ElementUI.Message('error')
}
return Promise.reject
})
export default request
login.js
代码语言:javascript复制import request from '@/utils/http.js'
/**
* 获取验证码
*/
export function code () {
return request({
url: '/getCode',
method: 'get'
})
}
/**
* 登录
*/
export function loginAPI (loginInfo) {
return request({
url: '/login',
method: 'post',
data: {
loginInfo
}
})
}
/**
* 获取菜单
*/
export function getMenu () {
return request({
url: '/sys/getMenu',
method: 'post'
})
}
mock.js
代码语言:javascript复制import Mock from 'mockjs'
const Random = Mock.Random
const R = {
code: 200,
message: '执行成功',
data: null
}
// 获取验证码
Mock.mock('/getCode', 'get', () => {
R.data = {
token: Random.string(32),
imageUri: Random.dataImage('100x100', '8878')
}
return R
})
// 登录
Mock.mock('/login', 'post', (value) => {
console.log(value)
R.data = {
token: 'token'
}
return R
})
// 获取菜单栏信息
Mock.mock('/sys/getMenu', 'post', () => {
const menu = [{
id: 1,
title: '系统设置',
name: 'settings',
path: '/sys',
icon: 'el-icon-setting',
component: '/sys/SysSettings.vue',
children: [
{
id: 2,
title: '用户管理',
name: 'user',
path: '/sys/user',
component: '/sys/UserInfo.vue',
icon: 'el-icon-user'
},
{
id: 3,
title: '角色管理',
name: 'role',
path: '/sys/role',
component: '/sys/RoleInfo.vue',
icon: 'el-icon-menu'
},
{
id: 4,
title: '权限管理',
name: 'menu',
path: '/sys/menu',
component: '/sys/MenuInfo.vue',
icon: 'el-icon-menu'
}
]
}]
const role = []
R.data = { menu, role }
return R
})
vuex相关代码
menu.js
代码语言:javascript复制import Vue from 'vue'
import Vuex from 'vuex'
import { getMenu } from '@/api/login.js'
Vue.use(Vuex)
export default {
state: {
menuList: [],
flag: false
},
getters: {
},
mutations: {
updateMenu (state, value) {
state.menuList = value
},
updateFlag (state, value) {
state.flag = value
}
},
actions: {
async httpGetMenu (store) {
const { data } = await getMenu()
store.commit('updateMenu', data.data.menu)
store.commit('updateFlag', true)
}
}
}
index.js
代码语言:javascript复制import Vue from 'vue'
import Vuex from 'vuex'
import menu from '@/store/modules/Menu.js'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
token: ''
},
getters: {
},
mutations: {
updateToken (state, value) {
state.token = value
localStorage.setItem('token', value)
},
restState (stste) {
stste.token = ''
}
},
actions: {
},
modules: {
namespaced: true,
menu
}
})
vue-router
代码语言:javascript复制import Vue from 'vue'
import VueRouter from 'vue-router'
import UserLogin from '@/views/UserLogin.vue'
import HomeIndex from '@/views/HomeIndex.vue'
import store from '@/store/index.js'
Vue.use(VueRouter)
const routes = [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
name: 'login',
component: UserLogin
},
{
path: '/home',
name: 'home',
component: HomeIndex,
children: []
}
]
const router = new VueRouter({
routes
})
router.beforeEach(async (to, form, next) => {
const flag = store.state.menu.flag
if (!flag) {
await store.dispatch('httpGetMenu')
const menuList = store.state.menu.menuList
for (const i in menuList) {
if (menuList[i].children) {
for (let j = 0; j < menuList[i].children.length; j ) {
const childrenMenu = {
path: menuList[i].children[j].path,
name: menuList[i].children[j].name,
children: []
}
childrenMenu.component = () => import('@/views' menuList[i].children[j].component)
router.addRoute('home', childrenMenu)
next({ ...to, replace: true })
}
}
}
}
next()
})
// 获取原型对象push函数
const originalPush = VueRouter.prototype.push
// 获取原型对象replace函数
const originalReplace = VueRouter.prototype.replace
// 修改原型对象中的push函数
VueRouter.prototype.push = function push (location) {
return originalPush.call(this, location).catch(err => err)
}
// 修改原型对象中的replace函数
VueRouter.prototype.replace = function replace (location) {
return originalReplace.call(this, location).catch(err => err)
}
export default router
home.vue
代码语言:javascript复制<template>
<div class="home_root">
<el-container>
<el-header
>物业管理
<el-dropdown :hide-on-click="false">
<span class="el-dropdown-link">
设置<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item @click.native="loginOut()">退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-header>
<el-container>
<el-aside width="200px">
<el-col>
<el-menu
default-active="2"
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
>
<el-submenu
:index="menu.id ''"
v-for="menu in menuList"
:key="menu.id"
>
<template slot="title">
<i :class="menu.icon"></i>
<span>{{ menu.title }}</span>
</template>
<el-menu-item
:index="children.id ''"
v-for="children in menu.children"
:key="children.id"
>
<template slot="title">
<div @click="openUri(children.path)">
<i :class="children.icon"></i>
<span slot="title">{{ children.title }}</span>
</div>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
</el-col>
</el-aside>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
export default {
computed: {
menuList () {
return this.$store.state.menu.menuList
}
},
methods: {
handleClose (tag) {
this.tags.splice(this.tags.indexOf(tag), 1)
},
openUri (uri) {
this.$router.push(uri)
},
loginOut () {
console.log('loginOut')
localStorage.clear()
sessionStorage.clear()
this.$store.commit('restState')
this.$router.push('/')
}
}
}
</script>
<style lang="less" scoped>
.home_root {
padding: 0;
margin: 0;
height: 100vh;
}
.el-container {
padding: 0;
margin: 0;
height: 100%;
}
.el-header,
.el-footer {
background-color: #b3c0d1;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #d3dce6;
color: #333;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: #e9eef3;
color: #333;
// text-align: center;
// line-height: 160px;
padding: 0;
}
body > .el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
.el-dropdown {
float: right;
}
.el-dropdown-link {
cursor: pointer;
color: #060606;
}
.el-icon-arrow-down {
font-size: 12px;
}
.el-col-24 {
height: 100%;
.el-menu {
height: 100%;
}
}
</style>