本节目标
点击收起
这里菜单渲染 暂时使用router/index.ts里的路由表 路由表里meta里面需要提供title icon 作为菜单项信息,icon是我们自己的svg文件名称
2-1 Sidebar导入路由表
sidebar组件导入路由表,根据routes循环SidebarItem组件

<template><div><!-- 测试展开收起 --><h6 @click="isCollapse=!isCollapse">展收测试</h6><el-menuclass="sidebar-container-menu"mode="vertical"router:default-active="activeMenu":background-color="scssVariables.menuBg":text-color="scssVariables.menuText":active-text-color="scssVariables.menuActiveText":collapse="isCollapse":collapse-transition="true"><sidebar-itemv-for="route in menuRoutes":key="route.path":item="route":base-path="route.path"/></el-menu></div></template><script lang="ts">import { defineComponent, computed, ref } from 'vue'import { useRoute } from 'vue-router'import variables from '@/styles/variables.scss'// 导入路由表import { routes } from '@/router'import SidebarItem from './SidebarItem.vue'export default defineComponent({name: 'Sidebar',components: {SidebarItem},setup() {const route = useRoute() // 等价于 this.$route// 根据路由路径 对应 当前激活的菜单const activeMenu = computed(() => {const { path } = routereturn path})// scss变量const scssVariables = computed(() => variables)// 展开收起状态 稍后放storeconst isCollapse = ref(false)// 渲染路由const menuRoutes = computed(() => routes)return {// 不有toRefs原因 缺点在这里 variables里面变量属性感觉来源不明确 不知道有哪些变量值// ...toRefs(variables),scssVariables,isCollapse,activeMenu,menuRoutes}}})</script>
2-2 实现SidebarItem组件
<template><div class="sidebar-item-container"><!-- 一个路由下只有一个子路由的时候 只渲染这个子路由 --><templatev-if="theOnlyOneChildRoute && !theOnlyOneChildRoute.children"><el-menu-item:index="resolvePath(theOnlyOneChildRoute.path)"><svg-iconv-if="icon"class="menu-icon":icon-class="icon"></svg-icon><template #title><span>{{ theOnlyOneChildRoute.meta.title }}</span></template></el-menu-item></template><!-- 多个子路由时 --><el-submenuv-else:index="resolvePath(item.path)"popper-append-to-body><template #title><svg-iconv-if="item.meta.icon"class="menu-icon":icon-class="item.meta.icon"></svg-icon><span class="submenu-title">{{ item.meta.title }}</span></template><sidebar-itemv-for="child in item.children":key="child.path":is-nest="true":item="child":base-path="resolvePath(child.path)"></sidebar-item></el-submenu></div></template><script lang="ts">import { defineComponent, PropType, computed, toRefs } from 'vue'import { RouteRecordRaw } from 'vue-router'import path from 'path'export default defineComponent({name: 'SidebarItem',props: {item: { // 当前路由(此时的父路由)type: Object as PropType<RouteRecordRaw>,required: true},basePath: { // 父路由路径(子路由路径如果是相对的 要基于父路径)type: String,required: true}},setup (props) {const { item } = toRefs(props)// 渲染菜单主要先看子路由// 比如我们的路由 一级路由一般都是layout组件 二级路由才是我们考虑要渲染成菜单的// 子路由数量const showingChildNumber = computed(() => {// hidden路由排除掉 只算可渲染子路由const children = (props.item.children || []).filter(child => {if (child.meta && child.meta.hidden) return falsereturn true})return children.length})// 要渲染的单个路由 如果该路由只有一个子路由 默认直接渲染这个子路由// theOnlyOneChildRoute直接通过el-menu-item组件来渲染const theOnlyOneChildRoute = computed(() => {// 多个children时 直接return null 多children需要用el-submenu来渲染并递归if (showingChildNumber.value > 1) {return null}// 只有一个子路由 还要筛选路由meta里有无hidden属性 hidden:true则过滤出去 不用管// 路由meta里我们会配置hidden属性表示不渲染成菜单,比如login 401 404页面是不渲染成菜单的if (item.value.children) {for (const child of item.value.children) {if (!child.meta || !child.meta.hidden) {return child}}}// showingChildNumber === 0 无可渲染的子路由 (可能有子路由 hidden属性为true)// 无可渲染chiildren时 把当前路由item作为仅有的子路由渲染return {...props.item,path: '' // resolvePath避免resolve拼接时 拼接重复}})// menu iconconst icon = computed(() => {// 子路由 如果没有icon就用父路由的return theOnlyOneChildRoute.value?.meta?.icon || (props.item.meta && props.item.meta.icon)})// 利用path.resolve 根据父路径+子路径 解析成正确路径 子路径可能是相对的// resolvePath在模板中使用const resolvePath = (childPath: string) => {return path.resolve(props.basePath, childPath)}return {theOnlyOneChildRoute,icon,resolvePath}}})</script><style lang="scss">.sidebar-item-container {.menu-icon { // icon样式调整margin-right: 16px;margin-left: 5px;vertical-align: middle;}}</style>
2-3 sidebar css样式调整
src/styles/sidebar.scss
#app {.sidebar-container {height: 100%;background-color: $menuBg;// menu未收起时样式&-menu:not(.el-menu--collapse) {width: $sideBarWidth;}// 菜单收起时的样式调整.el-menu--collapse {// 隐藏submenu title.submenu-title {display: none;}}.el-submenu {.el-menu {.el-menu-item {background-color: $subMenuBg !important;&:hover {background-color: $subMenuHover !important;}}}}.el-menu {border: none;}}}
2-4 路由表里icon和title
路由表里 icon 和title名称大家改改试试
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'import Layout from '@/layout/index.vue'// 看作是异步获取路由export const asyncRoutes: Array<RouteRecordRaw> = [{path: '/documentation',component: Layout, // 布局组件作为一级路由redirect: '/documentation/index',children: [{path: '/documentation/index',name: 'Documentation',component: () => import(/* webpackChunkName: "documentation" */ '@/views/documentation/index.vue'),meta: {title: 'Documentation',icon: 'documentation'}}]},{path: '/guide',component: Layout,redirect: '/guide/index',children: [{path: 'index',name: 'Guide',component: () => import(/* webpackChunkName: "guide" */ '@/views/guide/index.vue'),meta: {title: 'Guide',icon: 'guide'}}]},{path: '/system',component: Layout,redirect: '/system/user',meta: {title: 'System',icon: 'lock'},children: [{path: 'menu',component: () => import(/* webpackChunkName: "menu" */ '@/views/system/menu.vue'),meta: {title: 'Menu Management'}},{path: 'role',component: () => import(/* webpackChunkName: "role" */ '@/views/system/role.vue'),meta: {title: 'Role Management'}},{path: 'user',component: () => import(/* webpackChunkName: "user" */ '@/views/system/user.vue'),meta: {title: 'User Management'}}]}]export const constantRoutes: Array<RouteRecordRaw> = [{path: '/',component: Layout,redirect: '/dashboard',children: [{path: 'dashboard',name: 'Dashboard',component: () => import(/* webpackChunkName: "dashboard" */ '@/views/dashboard/index.vue'),meta: {title: 'Dashboard',icon: 'dashboard'}}]}]export const routes = [...constantRoutes,...asyncRoutes]const router = createRouter({history: createWebHashHistory(),routes})export default router
本节参考源码
https://gitee.com/brolly/vue3-element-admin/commit/053e7956eb2a09ac218863b57a203a7fcae0fbec
现在后不够完善继续
