系列文章目录
- 系列介绍:Vue3 + Vite + TS 从零开始学习
- 项目搭建:(一) Vue3 + Vite + TS 项目搭建
- 实现动态菜单栏:(二) Vue3 + Element-Plus 实现动态菜单栏
- 实现动态面包屑:(三) Vue3 + Element-Plus 实现动态面包屑
- 实现动态标签页:(四) Vue3 + Element-Plus 实现动态标签页
- 实现动态主题色切换(demo):(五) Vue3 + Element-Plus 实现动态主题色切换
- 踩坑记录(持续更新):(六) Vue3 踩坑记录
文章目录
- 系列文章目录
- 一、引入依赖
- 二、目录结构
- 三、核心代码
-
- 1. auth-api.js
- 2. permission.js
- 3.sidebar.vue
- 4.router.js
- 四、最终效果
一、引入依赖
开始前请确保已经安装以下依赖:
- VueX
$ npm i vuex --save
- Vue-Router
$ npm i vue-router --save
- NProgress
$ npm i nprogress --save
二、目录结构
|-src -- 主目录
---|api -- Ajax请求统一存放目录
------|auth-api.js -- 路由数据获取接口
---|js -- JS脚本
------|permission.js -- NProgress进度条数据处理
---|layout -- 页面布局组件
------|sidebar.vue -- 侧边栏布局组件
---|store -- VueX
------|router.js -- 路由全局常量
三、核心代码
1. auth-api.js
import request from '@/js/request'
export default {
routers(data) {
return request.post('/routers', data)
}
}
2. permission.js
import router from '../router'
import store from '../store'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getCookie } from './cookie'
import Layout from '../layout/index.vue'
import ParentView from '../components/ParentView/index.vue'
NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/register']
router.beforeEach((to, from, next) => {
NProgress.start()
if (getCookie()) {
if (to.path === '/login') {
next({ path: '/' })
NProgress.done()
} else {
if (store.state.user.menus.length === 0) {
store.dispatch('GetInfo').then(res => {
const menuIds = res.data.menuIds
store.dispatch('GenerateRoutes', menuIds).then(routes => {
filterRoutes(routes)
routes.forEach(route => {
router.addRoute(route)
})
next({ ...to, replace: true })
})
}).catch(() => {
next()
})
} else {
next()
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next(`/login?redirect=${to.fullPath}`)
NProgress.done()
}
}
})
router.afterEach(() => {
NProgress.done()
})
const filterRoutes = (routes) => {
const accessRoutes = routes.filter(route => {
let modules = import.meta.glob('../views/**/*.vue')
if (route.component) {
if (route.component === 'ParentView') {
route.component = ParentView
} else if (route.component === 'Layout') {
route.component = Layout
} else {
route.component = modules[`../views/${route.component}.vue`]
}
}
if (route.children && route.children.length) {
filterRoutes(route.children)
}
return true
})
return accessRoutes
}
3.sidebar.vue
<template>
<el-aside width="210px" class="aside-wrapper">
<el-scrollbar>
<el-menu :default-active="route.path" mode="vertical" :collapse-transition="false" router class="menu-wrapper">
<el-sub-menu v-for="menu in menus" :key="menu.path" :index="menu.path">
<template #title>
<el-icon><component :is="menu.meta.icon" /></el-icon>
<span>{{ menu.name }}</span>
</template>
<el-menu-item v-for="child in menu.children" :key="child.path" :index="child.path">
<template #title>
<el-icon><component :is="child.meta.icon" /></el-icon>
<span>{{ child.name }}</span>
</template>
</el-menu-item>
</el-sub-menu>
</el-menu>
</el-scrollbar>
</el-aside>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { useStore } from 'vuex'
import { useRoute } from 'vue-router'
const store = useStore()
const route = useRoute()
const menus = store.state.router.accessRoutes
</script>
4.router.js
import { authApi } from '@/api'
import constantRoutes from '@/router/routes'
const router = {
state: {
routes: [],
accessRoutes: []
},
mutations: {
SET_ROUTES: (state, routes) => {
state.routes = routes
},
SET_ACCESSROUTES: (state, accessRoutes) => {
state.accessRoutes = accessRoutes
}
},
actions: {
GenerateRoutes({ commit }, roleIds) {
return new Promise(resolve => {
authApi.routers(roleIds).then(res => {
const accessRoutes = res.data
filterRoutes('', accessRoutes)
const routes = constantRoutes.concat(accessRoutes)
commit('SET_ROUTES', routes)
commit('SET_ACCESSROUTES', accessRoutes)
resolve(routes)
})
})
}
}
}
const filterRoutes = (path, routes) => {
routes.forEach(route => {
const routePath = route.path
if (route.parentId !== '0') {
route.path = path + "/" + routePath
}
if (route.children && route.children.length) {
filterRoutes(routePath, route.children)
}
})
}
export default router