在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

Logo

快速构建 Web 应用程序

更多推荐