Vue3 Element Plus 应用开发实战2
本节实战内容:对 Element Plus 的菜单组件进行封装,实现一个无限级菜单组件。
首先,我们来分析一下 Element Plus 中菜单的基本使用方法。
1.Element Plus 菜单组件
<el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" default-active="2" text-color="#fff" @open="handleOpen" @close="handleClose" > <el-sub-menu index="1"> <template #title> <el-icon><location /></el-icon> <span>Navigator One</span> </template> <el-menu-item-group title="Group One"> <el-menu-item index="1-1">item one</el-menu-item> <el-menu-item index="1-2">item one</el-menu-item> </el-menu-item-group> <el-menu-item-group title="Group Two"> <el-menu-item index="1-3">item three</el-menu-item> </el-menu-item-group> <el-sub-menu index="1-4"> <template #title>item four</template> <el-menu-item index="1-4-1">item one</el-menu-item> </el-sub-menu> </el-sub-menu> <el-menu-item index="2"> <el-icon><icon-menu /></el-icon> <span>Navigator Two</span> </el-menu-item> <el-menu-item index="3" disabled> <el-icon><document /></el-icon> <span>Navigator Three</span> </el-menu-item> <el-menu-item index="4"> <el-icon><setting /></el-icon> <span>Navigator Four</span> </el-menu-item> </el-menu>
效果:
2.封装思路
分析:
在Element Plus的菜单组件中,由el-menu、el-sub-menu、el-menu-item、el-menu-item-group等4个组件构成。我们对菜单组件的封装目的是为了解决从数据表中读取菜单配置数据后动态地显示菜单。所以在子组件中需要封装el-sub-menu、el-menu-item组件就足够了。
如何封装?
按照需求,菜单的层级是事先不确定的,所以简单地使用v-for做循环迭代无法实现我们的目的,所以只能采用递归的方法来实现。在Element Plus的菜单中,图标已经从vue2的字符串表示改为组件,同时还需要当单击菜单时子组件向父组件传递对应单击的菜单,结合前面的文章《 Vue3 Element Plus 动态图标》、《 Vue3子组件向父组件返回数据》即可解决菜单的显示问题及事件处理问题。
实现思路:
1.新建一个组件,名称为TreeMenu
2.组件属性:menudata,类型为数组
3.触发事件:call_back
4.组件中,如果菜单项具有children属性,则该菜单项为el-sub-menu,并且递归调用组件自身,否则为el-menu-item
5.在el-menu-item组件上实现向父组件返回单击的菜单
3.无限级菜单组件封装代码
<template> <label v-for="menu in menudata" :key="menu.func_id"> <el-sub-menu :index="menu.func_id" v-if="menu.children"> <template #title> <el-icon v-if="menu.icon"><component :is="menu.icon"/></el-icon> <span>{{ menu.func_name }}</span> </template> <!--递归调用--> <tree-menu :menudata="menu.children" @call_back="next_call_back"></tree-menu> </el-sub-menu> <el-menu-item :index="menu.func_id" v-else @click="menu_item_clicked(menu)"> <el-icon v-if="menu.icon"><component :is="menu.icon"/></el-icon> <span>{{menu.func_name}}</span> </el-menu-item> </label> </template> <script> export default { name: "TreeMenu", props: { menudata: { type: Array } }, emits: [ 'call_back' ], setup (props, context) { function menu_item_clicked (menu) { context.emit('call_back', menu) } function next_call_back (menu) { context.emit('call_back', menu) } return {menu_item_clicked, next_call_back} } } </script> <style scoped> </style>
4.父组件中调用
<template> <el-menu active-text-color="#ffd04b" background-color="#313743" class="el-menu-vertical-demo" text-color="#fff" > <tree-menu :menudata="menus" @call_back="tree_menu_call_back"/> </el-menu> </template> <script> import TreeMenu from '../components/treemenu/TreeMenu.vue' export default { name: 'App', components: { TreeMenu }, data () { return { menus: [] } }, methods: { tree_menu_call_back (menu) { console.log(menu) if (menu.action) { // 路由跳转 } } } } </script> <style scoped> </style>
5.使用该自定义组件实现的菜单实例
如下图: