在Vue项目中,尤其是后台管理系统里面,不同用户登录进去显示的路由页面是不同的,这个时候就要用到我们的动态路由了,根据后台返回的路径来决定显示哪些路由页面
案例效果如下,第一个是管理员登录,第二个是普通用户登录
我们这个项目是用mock模拟的后台数据,所以第一步先写一下这个mock数据
yarn add mockjs
创建一个mock文件,文件里面创建一个index.js
index.js
import Mock from 'mockjs';
import permissionApi from './permission'
// 设置延时
Mock.setup({
timeout: '200-1000'
})
// 接口
Mock.mock(/\/permission\/getMenu/, 'post', permissionApi.getMenu)
再创建一个permission.js
import Mock from 'mockjs'
export default {
getMenu: config => {
const { username, password } = JSON.parse(config.body)
console.log(JSON.parse(config.body))
// 先判断用户是否存在
if (username === 'admin' || username === 'wp') {
// 判断账号和密码是否对应
if (username === 'admin' && password === '123456') {
return {
code: 20000,
data: {
menu: [
{
path: '/',
name: 'home',
label: '首页',
icon: 's-home',
url: 'Home/Home'
},
{
path: '/video',
name: 'video',
label: '视频管理页',
icon: 'video-play',
url: 'VideoManage/VideoManage'
},
{
path: '/user',
name: 'user',
label: '用户管理页',
icon: 'user',
url: 'UserManage/UserManage'
},
{
label: '其他',
icon: 'location',
children: [
{
path: '/page1',
name: 'page1',
label: '页面1',
icon: 'setting',
url: 'Other/PageOne'
},
{
path: '/page2',
name: 'page2',
label: '页面2',
icon: 'setting',
url: 'Other/PageTwo'
}
]
}
],
token: Mock.Random.guid(),
message: '获取成功'
}
}
} else if (username === 'wp' && password === '123456') {
return {
code: 20000,
data: {
menu: [
{
path: '/',
name: 'home',
label: '首页',
icon: 's-home',
url: 'Home/Home'
},
{
path: '/video',
name: 'video',
label: '视频管理页',
icon: 'video-play',
url: 'VideoManage/VideoManage'
}
],
token: Mock.Random.guid(),
message: '获取成功'
}
}
} else {
return {
code: -999,
data: {
message: '密码错误'
}
}
}
} else {
return {
code: -999,
data: {
message: '用户不存在'
}
}
}
}
}
数据弄好之后我们就来看一下路由怎么配置,后台管理第一个页面肯定是一个登录页,所以我们的静态路由只需要一个
router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/login',
name:'login',
component: () => import('../views/Login/Login.vue')
}
]
const router = new VueRouter({
routes
})
export default router
项目还用到了vuex
创建一个index.js入口
import Vue from 'vue'
import Vuex from 'vuex'
import tab from './tab'
import user from './user'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
tab,
user
}
})
创建一个tab.js
import Cookie from 'js-cookie'
export default {
state: {
isCollapse: false,
menu: [],
currentMenu: null,
tabsList: [{
id: 1,
name: 'home',
path: "/",
label: "首页",
icon: "home",
}]
},
mutations: {
// 动态路由设置
setMenu(state, val) {
state.menu = val
Cookie.set('menu', JSON.stringify(val))
},
// 清除cookid
clearMenu(state) {
state.menu = []
Cookie.remove('menu')
},
// 添加
addMenu(state, router) {
// 查看是否
if (!Cookie.get('menu')) {
return
}
let menu = JSON.parse(Cookie.get('menu'))
state.menu = menu
let currentMenu = [
{
path: '/',
component: () => import(`@/views/Mine`),
children: []
}
]
menu.forEach(item => {
if (item.children) {
item.children = item.children.map(item => {
item.component = () => import(`@/views/${item.url}`)
return item
})
currentMenu[0].children.push(...item.children)
} else {
item.component = () => import(`@/views/${item.url}`)
currentMenu[0].children.push(item)
}
})
router.addRoutes(currentMenu)
},
},
actions: {},
}
用到了cookie,安装一下即可
yarn add js-cookie
创建一个user.js
import Cookie from 'js-cookie'
export default {
state: {
token: ''
},
mutations: {
setToken(state, val) {
state.token = val
Cookie.set('token', val)
},
clearToken(state) {
state.token = ''
Cookie.remove('token')
},
getToken(state) {
state.token = Cookie.get('token')
}
},
actions: {}
}
由于项目用到了element-ui,可以安装一下
接下来就是我们的登录页面,Login.vue
<template>
<div style="padding: 20px">
<el-form :model="form" label-width="120">
<el-form-item label="用户名">
<el-input v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password" type="password"></el-input>
</el-form-item>
<el-form-item align="center">
<el-button type="primary" @click="login">登录</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
form: {
username: '',
password: ''
}
}
},
methods: {
login() {
this.$http.post('api/permission/getMenu', this.form).then(res => {
res = res.data
console.log(res)
if (res.code === 20000) {
this.$store.commit('clearMenu')
this.$store.commit('setMenu', res.data.menu)
this.$store.commit('setToken', res.data.token)
this.$store.commit('addMenu', this.$router)
this.$router.push({ name: 'home' })
} else {
this.$message.warning(res.data.message)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.el-form {
width: 50%;
margin: auto;
padding: 45px;
height: 450px;
background-color: #fff;
}
</style>
再就是我一开始展示的效果组件,显示几个路由
CommonAside.vue
<template>
<el-menu
default-active="2"
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
:collapse="isCollage"
>
<h3 v-show="!isCollage">刘刘后台管理系统</h3>
<h3 v-show="isCollage">刘刘</h3>
<el-menu-item v-for="item in noChildren" :key="item.id" :index="item.path" @click="clickMenu(item)">
<i :class="'el-icon-' + item.icon"></i>
<span slot="title">{{ item.label }}</span>
</el-menu-item>
<el-submenu index="index" v-for="item in hasChildren" :key="item.id">
<template slot="title">
<i class="el-icon-location"></i>
<span>{{ item.label }}</span>
</template>
<el-menu-item-group>
<el-menu-item
:index="subItem.path"
v-for="(subItem, subIndex) in item.children"
:key="subIndex"
@click="clickMenu(subItem)"
>{{ subItem.label }}</el-menu-item
>
</el-menu-item-group>
</el-submenu>
</el-menu>
</template>
<script>
export default {
name: "",
props: [""],
data() {
return {
asideMenu: [
{
id: 1,
name:'home',
path: "/",
label: "首页",
icon: "home",
},
{
id: 2,
name:'video',
path: "/video",
label: "视频管理",
icon: "video-play",
},
{
id: 3,
name:'user',
path: "/user",
label: "用户管理",
icon: "user",
},
{
id: 4,
name:'other',
label: "其他",
icon: "user",
children: [
{
path: "/page1",
name:'page1',
label: "演示页面1",
icon: "setting",
},
{
path: "/page2",
name:'page2',
label: "演示页面2",
icon: "setting",
},
],
},
],
};
},
components: {},
computed: {
// 计算是否有children
noChildren() {
return this.menu.filter((item) => !item.children);
},
hasChildren() {
return this.menu.filter((item) => item.children);
},
isCollage(){
return this.$store.state.tab.isCollapse
},
menu(){
return this.$store.state.tab.menu
}
},
methods: {
clickMenu(item) {
// 完成路由跳转
this.$router.push({name:item.name})
this.$store.commit("selectMenu", item);
},
},
};
</script>
<style lang="scss" scoped>
.el-menu {
height: 100%;
border: none;
h3{
color: #fff;
text-align: center;
line-height: 48px;
}
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
</style>
http的代码如下
import axios from 'axios'
// 创建一个axios实例
const service = axios.create({
// 请求超时时间
timeout: 3000,
})
// 请求拦截器
service.interceptors.request.use(
config => {
return config
},
err => {
console.log(err)
}
)
service.interceptors.response.use(
response => {
let res = {}
res.status = response.status
res.data = response.data
return res
},
err=>{
console.log(err)
}
)
export default service
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import http from './api/config'
import './mock'
Vue.config.productionTip = false
Vue.prototype.$http = http
router.beforeEach((to, from, next) => {
// 防止刷新后vuex里丢失token
store.commit('getToken')
// 防止刷新后vuex里丢失标签列表tagList
store.commit('getMenu')
let token = store.state.user.token
// 过滤登录页,防止死循环
if (!token && to.name !== 'login') {
next({ name: 'login' })
} else {
next()
}
})
Vue.use(ElementUI);
new Vue({
router,
store,
created() {
store.commit('addMenu',router)
},
render: h => h(App)
}).$mount('#app')
源码我放在github了
https://github.com/lsh555/llhoutai