【Vue3项目实战】vue3项目基于el-menu封装左侧菜单栏组件

文章目录

  • 概述
  • 一、先看效果
      • 1.1 静态效果
      • 1.2 动态效果
  • 二、核心思路
  • 三、全量代码
      • 3.1 文件目录结构
      • 3.2 /sidebar/index.vue 中
      • 3.3 /sidebar/sidebarItem.vue 中
      • 3.4 路由表结构
  • 四、代码讲解
  • 五、SVG组件
  • 六、系列文章友链
      • 1、[配置husky、stylelint、commitlint,实现git提交前代码校验](http://t.csdn.cn/226Xn)
      • 2、[配置@路径别名,实现@代替/src](http://t.csdn.cn/mMEwO)
      • 3、[配置 vue-router路由跳转,并完成路由模块化](http://t.csdn.cn/4r1ht)
      • 4、[配置vue-i18n中英文切换,完成国际化](http://t.csdn.cn/xyOaV)
      • 5、[配置滚动条样式](http://t.csdn.cn/cUkdA)
      • 6、[项目引入Element-plus,并配置按需自动导入](http://t.csdn.cn/mxdsS)
      • 7、[配置页面切换,路由跳转过渡动画](http://t.csdn.cn/LEKk6)
      • 8、[配置nprogress,实现路由加载进度条](http://t.csdn.cn/inFOa)

概述

做什么:封装通用左侧菜单栏组件
怎么做:使用 Element-Plus 组件库中的 el-menu组件进行二次封装
技术栈:Vue3 + Ts + Vite,且采用 setup 语法糖写法
准备工作:请各位自行引入Element-plus组件库,本文中有用到 svg组件,svg组件封装教程请看第五点

一、先看效果

1.1 静态效果

【Vue3项目实战】vue3项目基于el-menu封装左侧菜单栏组件_第1张图片

1.2 动态效果

【Vue3项目实战】vue3项目基于el-menu封装左侧菜单栏组件_第2张图片


二、核心思路

查看 Element-plus 组件库中的 el-menu 组件,不难发现,菜单栏大致可以分为两类,类是有子菜单的,一类是无子菜单的
所以我们将对这两类进行分情况设计,再结合递归,即可完成根据路由列表,动态渲染菜单栏

【Vue3项目实战】vue3项目基于el-menu封装左侧菜单栏组件_第3张图片


三、全量代码

3.1 文件目录结构

【Vue3项目实战】vue3项目基于el-menu封装左侧菜单栏组件_第4张图片

3.2 /sidebar/index.vue 中

<script lang="ts" setup>
// sidebarItem 项组件
import SideBarItem from './sidebarItem.vue';
import { useRouter } from 'vue-router';
// 拿到路由列表,过滤我们不想要的
const router = useRouter();
const routerList = router.getRoutes().filter((v) => v.meta && v.meta.isShow);
</script>
<template>
	<div class="sidebar">
		<!-- 项目名称及logo -->
		<div class="sidebar-logo flex-center">
			<svg-icon icon-class="logo" />
			<span>VitalityAdmin</span>
		</div>

		<!-- 导航菜单 -->
		<el-menu
			active-text-color="#fff"
			background-color="#001529"
			:default-active="$route.path"
			text-color="#999"
			:unique-opened="true"
			router>
			
            <!-- 引入子组件 -->
			<SideBarItem :routerList="routerList" />
		</el-menu>
		
		<!-- active-text-color:当前菜单项被选中时,字体的颜色 -->
		<!-- background-color:这个menu菜单的背景色 -->
		<!-- default-active:	当前激活菜单的 index -->
		<!-- text-color:菜单项字体颜色 -->
		<!-- unique-opened:unique-opened	是否只保持一个子菜单的展开 -->
		<!-- router:是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转 -->
	</div>
</template>
<style lang="scss" scoped>
.sidebar {
	height: 100%;
	.sidebar-logo {
		height: 48px;
		background-color: #002140;
		color: #fff;
		font-weight: 700;
		line-height: 48px;
		text-align: center;
		font-size: 20px;
	}
	.el-menu {
		height: calc(100% - 48px);
		border-right: 0;
		overflow: auto;
	}
}
</style>

3.3 /sidebar/sidebarItem.vue 中

<script setup lang="ts">
import { RouteRecordRaw } from 'vue-router';
// 做类型限制,解决ts类型报错
type CustomRouteRecordRaw = RouteRecordRaw & {
	meta: {
		isShow?: boolean;
	};
};
const props = defineProps({
	// 拿到父组件传递过来的路由列表进行渲染
	routerList: {
		type: Array as () => CustomRouteRecordRaw[],
		required: true
	}
});
</script>
<template>
	<template v-for="item in props.routerList" :key="item.path">
		<!-- 当该菜单项有子菜单时 -->
		<el-sub-menu :index="item.path" v-if="item.children && item.children.length > 0">
			<template #title v-if="item.meta.icon">
				<!-- 菜单项图标,我此处用的是全局封装的 svg组件 -->
				<el-icon><svg-icon :icon-class="item.meta.icon" /></el-icon>
				<!-- 菜单项名称,在路由中定义好 -->
				<span>{{ item.meta.title }}</span>
			</template>
			<!-- 若路由中未定义菜单项icon,则仅展示名称--(我的仅一级菜单有图标) -->
			<template #title v-else>{{ item.meta.title }}

			<!-- 递归遍历-自己调用自己(核心代码) -->
			<sidebarItem :routerList="( item.children as CustomRouteRecordRaw[])" />
		</el-sub-menu>

		<!-- 当前菜单项无子菜单 -->
		<el-menu-item :index="item.path" v-else>
			<!-- 与上面注释大致相同,不多做额外注释 -->
			<template v-if="item.meta.icon">
				<el-icon><svg-icon :icon-class="item.meta.icon" /></el-icon>
				<span>{{ item.meta.title }}</span>
			</template>
			<template v-else>
				{{ item.meta.title }}
			</template>
		</el-menu-item>
	</template>
</template>

<style scoped lang="scss">
.is-active {
	background: #409eff;
	font-weight: 700;
}

.el-menu-item {
	&:hover {
		color: #fff;
		font-weight: 700;
	}
}

.el-menu--collapse {
	.el-menu-item {
		justify-content: center;
	}
}

// 下列代码是用于兼容horizontal所写,酌情删或留
.el-menu--horizontal {
	.el-menu-item.is-active {
		background-color: transparent !important;
		border-bottom: 2px solid #409eff !important;

		.el-icon,
		span {
			color: #409eff !important;
		}
	}

	.el-sub-menu.is-active {
		.el-sub-menu__title {
			border: 0 !important;
		}

		.el-icon,
		span {
			color: #409eff !important;
		}
	}
}
</style>


3.4 路由表结构

isShow: true, // 控制当前项是否在菜单栏中渲染出来,比如你写了 login 页面的路由,但是并不希望 login在menu菜单中渲染出来,即可设为false
title: ‘首页’, // menu菜单项的名称,没啥好说的
icon: ‘menu-home’ // menu菜单项的图标,我此处是与封装好的 svg 组件结合使用的

export default [
	{
		path: '/layout',
		name: 'layoutIndex',
		component: () => import('@/layout/index.vue'),
		children: [
			{
				path: '/home',
				name: 'homeIndex',
				component: () => import('@/views/home/index.vue'),
				meta: {
					isShow: true, // 控制当前项是否在菜单栏中渲染出来,比如你写了 login 页面的路由,但是并不希望 login在menu菜单中渲染出来,即可设为false
					title: '首页', // menu菜单项的名称,没啥好说的
					icon: 'menu-home' // menu菜单项的图标,我此处是与封装好的 svg 组件结合使用的
				}
			},
			{
				path: '/echarts',
				name: 'echartIndex',
				// component: () => import('@/views/echarts/index.vue'),
				meta: {
					isShow: true,
					title: 'Echarts页',
					icon: 'menu-echarts'
				},
				children: [
					{
						path: '/echarts/barCharts',
						name: 'barCharts',
						component: () => import('@/views/echarts/barCharts.vue'),
						meta: {
							title: '柱状图'
						}
					},
					{
						path: '/echarts/pieCharts',
						name: 'pieCharts',
						component: () => import('@/views/echarts/pieCharts.vue'),
						meta: {
							title: '饼图'
						}
					}
				]
			},
			{
				path: '/package',
				name: 'packageIndex',
				component: () => import('@/views/package/index.vue'),
				meta: {
					isShow: true,
					title: '组件',
					icon: 'menu-package'
				}
			},
			{
				path: '/menu',
				name: 'menuIndex',
				redirect: '/menu/menu-1',
				meta: {
					isShow: true,
					title: '一级菜单',
					icon: 'menu-package'
				},
				children: [
					{
						path: '/menu/menu-1',
						name: 'menu-1',
						component: () => import('@/views/menu/menu1.vue'),
						meta: {
							title: '二级菜单-1'
						}
					},
					{
						path: '/menu/menu-2',
						name: 'menu-2',
						component: () => import('@/views/menu/menu2.vue'),
						meta: {
							title: '二级菜单-2'
						},
						children: [
							{
								path: '/menu/menu-2/children',
								name: 'menu3',
								component: () => import('@/views/menu/menu3.vue'),
								meta: {
									title: '三级菜单'
								}
							}
						]
					}
				]
			}
		]
	}
];


四、代码讲解

【Vue3项目实战】vue3项目基于el-menu封装左侧菜单栏组件_第5张图片

【Vue3项目实战】vue3项目基于el-menu封装左侧菜单栏组件_第6张图片


五、SVG组件

本文不展开讲解 svg组件 的封装与使用,有需要的朋友欢迎参考下面的 svg组件 封装教程

svg组件封装教程:http://t.csdn.cn/uYsSJ

六、系列文章友链

本系列文章记录了从零到一 搭建 Vue3+Ts+Vite 项目的全过程
包括但不限于项目配置、组件封装、过渡动画等
系列文章持续更新中~~‍,有任何问题欢迎评论区留言
最后,希望本文都能对你有一点帮助,点赞收藏不迷路

1、配置husky、stylelint、commitlint,实现git提交前代码校验

2、配置@路径别名,实现@代替/src

3、配置 vue-router路由跳转,并完成路由模块化

4、配置vue-i18n中英文切换,完成国际化

5、配置滚动条样式

6、项目引入Element-plus,并配置按需自动导入

7、配置页面切换,路由跳转过渡动画

8、配置nprogress,实现路由加载进度条

你可能感兴趣的:(Vue3项目实战,Element,Plus,javascript,前端,vue.js)