Vue2动态路由

应用场景:

 

一般管理端的菜单栏是根据登录用户角色不同,动态生成的,在vue中我们不止菜单栏需要动态生成,同时我们路由也需要动态生成。

使用到的组件:

组件名称组件版本组件作用
axios1.3.4用于发送请求获取数据
element-ui2.15.13前端ui组件库,制作页面使用
vue-router3.5.1vue路由组件
vuex3.6.2路由状态管理
mockjs1.1.0模拟后台返回数据接口

代码实现:

项目结构:

axios相关代码

http.js

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

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

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

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

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

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

<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>

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半夜燃烧的香烟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值