菜单 Menu
实现思路
根据路由渲染菜单,路由信息通过登录后,后端返回获得
路由
以下基于Vue 3.x 和 vue Router 4.x
\src\router\index.js
const routes = [
// 重定向404页面
{
path: '/:pathMatch(.*)*',
redirect: { name: 'index' },
hideen: true,
meta: {
name: "首页"
},
},
// 登录页
{
path: '/login',
name: 'login',
hideen: true,
component: login,
meta: {
name: "登录"
},
},
// 主页
{
path: '/',
name: 'layout',
component: layout,
redirect: { name: 'index' },
hideen: true,
meta: {
name: "首页"
},
children: [
{
path: '/index',
name: 'index',
component: index,
meta: {
name: "首页"
},
},
]
},
// 这里是各个业务的路由页面
{
path: '/assetManagement',
name: 'assetManagement',
component: layout,
meta: {
name: "资产"
},
children: [
{
path: 'index',
name: 'assetIndex',
component: assetIndex,
meta: {
name: "资产概览"
},
},
{
path: '/assetsList',
name: 'assetsList',
component: assetsList,
meta: {
name: "资产列表"
},
},
{
path: '/assetsReport',
name: 'assetsReport',
component: assetsReport,
meta: {
name: "资产报表"
},
},
],
},
]
子菜单
子菜单的作用,是自己递归生成二级、三级、… 、n级菜单,直到没有为止。
以下基于Vue 3.x 和 vue Router 4.x,以及ant-design-vue 2.x
<template>
<a-sub-menu :key="menuInfo.key" v-bind="$attrs">
<template #title>
<span>
<BarsOutlined /><span>{{ menuInfo.meta.name }}</span>
</span>
</template>
<template v-for="(item) in menuInfo.children" :key="item.path">
<template v-if="!item.children">
<a-menu-item :key="item.path">
<BarsOutlined />
<span>{{ item.meta.name }}</span>
</a-menu-item>
</template>
<template v-else>
<submenu :menu-info="item" :key="item.path" />
</template>
</template>
</a-sub-menu>
</template>
<script>
import {
BarsOutlined,
} from '@ant-design/icons-vue';
export default {
components: {
BarsOutlined,
},
name: 'submenu',
props: {
menuInfo: {
type: Object,
default: () => ({}),
},
},
}
</script>
<style>
</style>
主菜单
子菜单的最外层容器
以下基于Vue 3.x 和 vue Router 4.x,以及ant-design-vue 2.x
<template>
<!-- 菜单栏 -->
<a-menu id="baseMenu"
theme="dark"
mode="inline"
v-model:selectedKeys="selectedKeys"
@click="menuItemClick"
:inlineIndent="12">
<!-- 循环获取菜单 -->
<template v-for="(item) in menuItem" :key="item.path">
<!-- 权限控制,不显示隐藏的菜单,主要是过滤首页、登录页 -->
<template v-if="!item.hideen">
<!-- 没有子菜单 -->
<template v-if="!item.children">
<a-menu-item :key="item.path">
<BarsOutlined />
<span>{{ item.meta.name }}</span>
</a-menu-item>
</template>
<!-- 有子菜单 -->
<template v-else>
<submenu :menu-info="item" :key="item.path" />
</template>
</template>
</template>
</a-menu>
</template>
<script>
import { onMounted, reactive, ref, computed } from "vue";
// 引入ant-design-vue相关
import { BarsOutlined } from "@ant-design/icons-vue"; //引入图标组件,菜单栏图标
import { message, Result } from "ant-design-vue";
import { useRouter } from "vue-router"; //引入路由
import { useStore } from "vuex";
import { getMenu } from "/@/api/home/aside.js"; //引入获取菜单的api
import submenu from "/@/views/layout/sideBar/subMenu.vue";
export default {
name: "baseMenu",
components: {
BarsOutlined,
submenu,
},
setup() {
//data 菜单的选项
const store = useStore();
let selectedKeys = computed({
//当前已选择菜单key
get: () => {
store.state.menu.selectedKeys;
},
set: (val) => {},
});
//创建路由实例
const router = useRouter();
// 从路由里读取菜单
let menuItem = reactive(router.options.routes);
//function 菜单按钮点击事件
const menuItemClick = (itemKey) => {
// 1、提交修改已选择的菜单
store.dispatch("handleSelectedKeys", itemKey.key);
///2、然后跳转路由
router.push(itemKey.key);
};
return {
selectedKeys,
menuItem,
menuItemClick,
};
},
};
</script>
<style>
#baseMenu {
text-align: left;
}
</style>
=====================
标签页 Tab
方便用户选择最近使用的页面,以及部分功能弹出新页面进行操作。
通过ant-design-vue 2.x 的tab组件可以轻松实现
=====================
菜单、标签联动
实现思路
1、通过vuex储存标签,以及当前页的key,这个key会同时影响菜单和标签的当前选中激活的菜单、标签
state: () => ({
selectedKeyStore:"index", // 当前激活的页面的标签页、菜单
tabPanes: [ // 全局的标签页,主要是配置首页不可关闭
{ title: "首页", key: "index", closable: false },
],
}),
2、设置修改当前页的key的方法
mutations: {
// 修改当前激活页面的key
changeSelectedKeyStore(state,key){
state.selectedKeyStore = key
},
}
3、通过路由的导航守卫beforeEach,每次进入路由时,读取要进入页面的name属性,赋值给当前页的key。
这样的好处时,用户不管是点击menu,还是点击tab,还是刷新页面,都能保证当前激活的key都是准确的。
import { createRouter, createWebHistory } from 'vue-router';
import store from '/@/store/index.js'
router.beforeEach((to, from, next) => {
// 临时设置登录状态
let isLogin = true;
// 判断是否登录,登录了就跳转到正常页面,没登录就跳转登录页
if (to.name !== 'login' && !isLogin) {
console.log(`跳转到登录页`)
next({ name: 'login' })
} else {
store.commit('changeSelectedKeyStore', to.name)
next();
}
})