在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 = valCookie.set('menu', JSON.stringify(val))},// 清除cookidclearMenu(state) {state.menu = []Cookie.remove('menu')},// 添加addMenu(state, router) {// 查看是否if (!Cookie.get('menu')) {return}let menu = JSON.parse(Cookie.get('menu'))state.menu = menulet 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 = valCookie.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.dataconsole.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-menudefault-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: {// 计算是否有childrennoChildren() {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.statusres.data = response.datareturn 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 = falseVue.prototype.$http = httprouter.beforeEach((to, from, next) => {// 防止刷新后vuex里丢失tokenstore.commit('getToken')// 防止刷新后vuex里丢失标签列表tagListstore.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