【Vue3+Element Plus】根据动态路由生成菜单项(并使用 el-icon 图标)

前文回顾

【Vue3+Vite】使用 glob 生成动态路由

视图创建约定

视图目录结构

本文针对二级菜单项进行讲解。

视图目录结构

主页不需要用目录包裹,父菜单项目录只需要创建一个 page.ts 配置文件,里面的子目录是子菜单项。

视图目录结构2

菜单项配置

主页配置示例

export default {
	title: '主页',
	menuItem: {
		icon: 'home-filled'
	}
}

父菜单项配置示例

export default {
	title: '学习园地',
	menuItem: {
		icon: 'reading',
		isParent: true
	}
}

子菜单项配置示例

export default {
	title: '资源导航',
	menuItem: {
		icon: 'link'
	}
}

router/index.ts

路由、菜单项映射获取

// 调整路由的层级顺序,使父菜单项一定在子菜单项上面
routes.sort(function (a, b) {
	return a.name.localeCompare(b.name)
})

const routeMap: Map<string, RouteRecordRaw> = new Map()
const menuItemMap: Map<string, any> = new Map()

routes.forEach((route: any) => {
	// 父菜单项不设置 component(仅有一个文件夹和 page.ts),所以不让它加到路由里面
	if (route.component) {
		const title = route.meta.title
		routeMap.set(title, route)
	}

	if (route.meta.menuItem) {
		const name = route.name
		const path = route.path
		const icon = route.meta.menuItem.icon
		const title = route.meta.title
		const isParent = route.meta.menuItem.isParent

		if (isParent) {
			menuItemMap.set(name, {
				icon,
				title,
				childrens: []
			})
		} else {
			const parent = path.split('/')[1]
			// 如果存在这个父菜单项
			if (menuItemMap.has(parent)) {
				menuItemMap.get(parent).childrens.push({
					path,
					icon,
					title
				})
			} else {
				menuItemMap.set(name, {
					path,
					icon,
					title
				})
			}
		}
	}
})

导出菜单项数组

export const getMenuItems = () => {
	return Array.from(menuItemMap.values())
}

菜单项渲染组件

关于 el-menu 的菜单项高亮设置请移步:【Vue3+Pinia+Element Plus】el-menu :default-active 当前菜单项保持激活

<template>
	<el-menu mode="horizontal" :ellipsis="false" router menu-trigger="click" unique-opened :default-active="elMenuActive">
		<template v-for="(item, idx) in menuItems">
			<template v-if="!item.childrens">
				<el-menu-item :index="item.path" :key="idx">
					<el-icon>
						<component :is="item.icon"></component>
					</el-icon>
					<span>{{ item.title }}</span>
				</el-menu-item>
			</template>

			<template v-else>
				<el-sub-menu :index="idx" :key="idx">
					<template #title>
						<el-icon>
							<component :is="item.icon"></component>
						</el-icon>
						<span>{{ item.title }}</span>
					</template>
					<el-menu-item v-for="(item2, idx2) in item.childrens" :key="idx2" :index="item2.path">
						<el-icon>
							<component :is="item2.icon"></component>
						</el-icon>
						<span>{{ item2.title }}</span>
					</el-menu-item>
				</el-sub-menu>
			</template>
		</template>
	</el-menu>
</template>

<script setup lang="ts">
import { getMenuItems } from '@/router'
    
const menuItems = getMenuItems()
</script>

效果图

效果图

参考资料

[1] 老张前端. vue3动态组件[Z/OL]. https://www.bilibili.com/video/BV1Ju4y1H7Ri. 2023.

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值