菜单 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"; //引入获取菜单的apiimport submenu from "/@/views/layout/sideBar/subMenu.vue";export default {name: "baseMenu",components: {BarsOutlined,submenu,},setup() {//data 菜单的选项const store = useStore();let selectedKeys = computed({//当前已选择菜单keyget: () => {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: {// 修改当前激活页面的keychangeSelectedKeyStore(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();}})
