自己想手搭一个vue3+ts的后台管理项目,在构建导航栏的时候,发现根据路由权限信息动态配置导航栏,之前的vue2实现方案比较复杂于是自己利用递归组件实现导航栏
1.首先创建路由
export const constantRoute = [
{
path: '/login',
component: () => import('@/views/login/index.vue'),
name: 'login',
meta: {
title: '登录',
hidden: true,
},
},
{
path: '/',
component: () => import('@/layout/index.vue'),
name: 'layout',
meta: {
title: '首页',
hidden: false,
},
children: [
{
path: '/home',
component: () => import('@/views/home/home.vue'),
name: 'home',
meta: {
title: '首页',
hidden: false,
},
},
{
path: '/home',
component: () => import('@/views/home/home.vue'),
name: 'home',
meta: {
title: '首页',
hidden: false,
},
},
],
},
{
path: '/404',
component: () => import('@/views/404/index.vue'),
name: '404',
meta: {
title: '404',
hidden: true,
},
},
{
path: '/:pathMatch(.*)*',
redirect: '/404',
name: 'Any',
meta: {
title: '任意路由',
hidden: true,
},
},
]
2.将路由信息引入store,后期可进行持续化存储
// 引入路由
import { constantRoute } from '@/router/routes'
// 创建用户相关的仓库
import { defineStore } from 'pinia'
const userStore = defineStore('user', {
state: () => {
return {
token: localStorage.getItem('TOKEN'),
//导航栏路由
menuRoutes: constantRoute
}
},
actions: {
// 用户登陆方法
userLogin(token: any) {
console.log(token)
userStore().token = token
localStorage.setItem('TOKEN', token)
},
},
getters: {},
})
// 对外暴露
export default userStore
2.创建一个导航栏组件
<!-- -->
<template>
<!-- <div class="">{{ menuList }}</div> -->
<!-- 循环menuList菜单路由的列表 -->
<div v-for="(item, index) in menuList" :key="index">
<el-sub-menu :index="item.path" v-if="item.children && !item.meta.hidden">
<template #title>{{ item.meta.title }}</template>
<Menu :menuList="item.children"></Menu>
</el-sub-menu>
<el-menu-item :index="item.path" v-if="!item.meta.hidden && !item.children">
<!-- <el-icon><icon-menu /></el-icon> -->
<span>{{ item.meta.title }}</span>
</el-menu-item>
</div>
</template>
<script lang="ts" setup>
import { onMounted } from 'vue'
defineProps({
menuList: {
type: Array,
// eslint-disable-next-line vue/require-valid-default-prop
default: [],
},
})
onMounted(() => {})
</script>
<!-- 嵌套路由需要再建个script导出Menu-->
<script lang="ts">
export default {
// eslint-disable-next-line vue/no-reserved-component-names
name: 'Menu',
}
</script>
<style lang="less" scoped></style>
3.在layout页面引入菜单栏
<template>
<div class="layout_container">
<div class="layout_slider">
<logo></logo>
<div>
<el-scrollbar class="nav">
<el-menu text-color="white" background-color="$base-menu-background">
//引入menu菜单组件
<menuNav :menuList="userStores.menuRoutes"></menuNav>
</el-menu>
</el-scrollbar>
</div>
</div>
<div class="layout_tabbar"></div>
<div class="layout_main"></div>
</div>
</template>
<script lang="ts" setup>
import logo from './logo/index.vue'
import menuNav from './menu/index.vue'
import userStore from '@/store/modules/user'
let userStores = userStore()
</script>
<style scoped lang="scss">
.layout_container {
width: 100vw;
height: 100vh;
background-color: w;
}
.layout_slider {
width: $base-menu-width;
height: 100%;
background-color: $base-menu-background;
}
.layout_tabbar {
position: fixed;
top: 0;
left: $base-menu-width;
width: calc(100% - $base-menu-width);
height: $base-tabbar-height;
background-color: #c111cc;
}
.layout_main {
position: fixed;
top: $base-tabbar-height;
left: $base-menu-width;
background-color: #0000;
width: calc(100% - $base-menu-width);
height: calc(100% - $base-tabbar-height);
padding: $base-main-padding;
overflow: auto;
}
.nav {
height: calc(100vh - $base-tabbar-height);
el-menu {
border-right: 0px;
}
}
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 50px;
margin: 10px;
text-align: center;
border-radius: 4px;
background: var(--el-color-primary-light-9);
color: var(--el-color-primary);
}
</style>