Vue3+ElementPlus 实现动态菜单

创建Menu数据库表

CREATE TABLE `menu`  (
  `menu_id` int NOT NULL AUTO_INCREMENT COMMENT '菜单编号',
  `menu_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '菜单名称',
  `menu_title` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '菜单标题',
  `menu_path` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '菜单路径',
  `menu_icon` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '菜单图标',
  `menu_parent_id` int NULL DEFAULT NULL COMMENT '菜单父级编号',
  `menu_order` int NULL DEFAULT NULL COMMENT '菜单排序',
  PRIMARY KEY (`menu_id`) USING BTREE
) 

添加数据

 

 后端处理数据

第一步,获取menu表中的所有数据

  <select id="selectAllMenu" resultMap="BaseResultMap">
    SELECT
        <include refid="AllColumn"></include>
    FROM `menu`
  </select>

第二步,对Menu实体类需要做一些修改,需要增加一个children成员变量,用来存放当前菜单的所有子级菜单信息

package com.zero.springbootmall.entity;

import java.util.List;

public class Menu {
    private Integer menuId;

    private String menuName;

    private String menuTitle;

    private String menuPath;

    private String menuIcon;

    private Integer menuParentId;

    private Integer menuOrder;

    private List<Menu> children;

    public List<Menu> getChildren() {
        return children;
    }

    public void setChildren(List<Menu> children) {
        this.children = children;
    }

    public Integer getMenuId() {
        return menuId;
    }

    public void setMenuId(Integer menuId) {
        this.menuId = menuId;
    }

    public String getMenuName() {
        return menuName;
    }

    public void setMenuName(String menuName) {
        this.menuName = menuName == null ? null : menuName.trim();
    }

    public String getMenuTitle() {
        return menuTitle;
    }

    public void setMenuTitle(String menuTitle) {
        this.menuTitle = menuTitle == null ? null : menuTitle.trim();
    }

    public String getMenuPath() {
        return menuPath;
    }

    public void setMenuPath(String menuPath) {
        this.menuPath = menuPath == null ? null : menuPath.trim();
    }

    public String getMenuIcon() {
        return menuIcon;
    }

    public void setMenuIcon(String menuIcon) {
        this.menuIcon = menuIcon == null ? null : menuIcon.trim();
    }

    public Integer getMenuParentId() {
        return menuParentId;
    }

    public void setMenuParentId(Integer menuParentId) {
        this.menuParentId = menuParentId;
    }

    public Integer getMenuOrder() {
        return menuOrder;
    }

    public void setMenuOrder(Integer menuOrder) {
        this.menuOrder = menuOrder;
    }

    @Override
    public String toString() {
        return "Menu{" +
                "menuId=" + menuId +
                ", menuName='" + menuName + '\'' +
                ", menuTitle='" + menuTitle + '\'' +
                ", menuPath='" + menuPath + '\'' +
                ", menuIcon='" + menuIcon + '\'' +
                ", menuParentId=" + menuParentId +
                ", menuOrder=" + menuOrder +
                ", children=" + children +
                '}';
    }
}

第三步,对获取到的所有菜单数据进行遍历,通过递归的方式给所有menuParentId为0的菜单的children赋值。最后通过流的方式过滤menuList集合,将menuList中menuParentId为0的菜单作为结果返回给前端。

@Override
    public Result queryMenu() {
        List<Menu> menuList = menuMapper.selectAllMenu();
        for (Menu menu : menuList) {
            if (Objects.equals(menu.getMenuParentId(),0)){ //当前菜单为一级菜单
                List<Menu> children = getAllChildren(menu.getMenuId());
                menu.setChildren(children);
            }
        }
        Stream<Menu> menuStream = menuList.stream().filter(item -> item.getMenuParentId() == 0);
        List<Menu> collect = menuStream.collect(Collectors.toList());
        System.out.println("++===>>>"+collect);
        return Result.success(collect);
    }

    private List<Menu> getAllChildren(Integer menuId) {
        List<Menu> menus = menuMapper.selectMenuByParentId(menuId);
        if (Objects.isNull(menus) || Objects.equals(menus.size(),0) ) return null;
        for (Menu menu : menus) {
            getAllChildren(menu.getMenuId());
        }
        return menus;
    }

 前端获取数据渲染

 首先,去ElementPlus官网去复制Menu组件的相关代码,并做一些修改。

<el-row class="tac">
    <el-col :span="24">
	    <el-menu
			class="el-menu-vertical-demo"
			:default-active="currentRouter"
			text-color="#fff"
			:collapse="isCollapse"	
			@select="handleSelect"
			router
			style="--el-menu-bg-color: #304156; --el-menu-hover-bg-color: rgb(38, 52, 69);"
			  >
			     <MenuTree :menuList="menuData"></MenuTree>
        </el-menu>  
    </el-col>
</el-row>
<script  setup>
import {onMounted, ref} from 'vue';
import { useRouter } from 'vue-router';
import {get,post} from '../api/api.js'
import MenuTree from './MenuTree.vue'
	const router = useRouter();
	const currentRouter = ref()
	const menuData = ref([])
	onMounted(()=>{
		getMenuData()
	})
	
	const getMenuData = async()=>{
		let result = await get("/menu/queryMenu")
		menuData.value = result.data
		console.log(menuData.value); // 打印后端传来的数据
	}
	
const handleSelect=(index)=>{
	 router.push(index);  // 当选中某菜单时进行路由跳转
}
</script>

 其次,创建MenuTree组件,通过父传子的方式,将后端传来的数据传给子组件,交给子组件去渲染。

<template>
    <div>
        <template v-for="item in props.menuList" :key="item.meunId">
            <!--      分为两种方式渲染:有子菜单和没有子菜单-->
            <el-sub-menu :index="String(item.menuPath)" v-if="item.children">
                <template #title>
                    <span>{{ item.menuTitle }}</span>
                </template>
                <!--  有子菜单的继续遍历(递归)-->
                <MenuTree :menuList="item.children"></MenuTree>
            </el-sub-menu>
            <!--  没有子菜单  -->
            <el-menu-item :index="String(item.menuPath)" v-if="!item.children">
                <span>{{ item.menuTitle }}</span>
            </el-menu-item>
        </template>
    </div>
</template>
 
 <script setup >
 import { defineProps, onMounted,computed } from 'vue'
 const props = defineProps(['menuList'])
 
 onMounted( () => {
	 console.log(props);
 })

 </script>
 
<style></style>

最后,在index.js文件中配置相对应的路由,就可以实现跳转了。

实现无限级侧边栏可以使用 Vue Router 中的嵌套路由,以及Element Plus中的菜单组件。具体实现步骤如下: 1. 在 Vue Router 中配置嵌套路由,例如: ```js const routes = [ { path: '/', component: Home, children: [ { path: 'about', component: About }, { path: 'products', component: Products, children: [ { path: 'category/:categoryId', component: Category } ] } ] } ] ``` 其中,`children` 表示该路由的子路由,可以无限嵌套下去。 2. 在侧边栏中使用 Element Plus 的菜单组件,并使用 `router-link` 标签指定路由。例如: ```html <el-menu-item index="/about"> <i class="el-icon-menu"></i> <span slot="title">关于我们</span> </el-menu-item> <el-submenu index="/products"> <template slot="title"> <i class="el-icon-goods"></i> <span>产品列表</span> </template> <el-menu-item v-for="category in categories" :key="category.id" :index="'/products/category/' + category.id" > {{ category.name }} </el-menu-item> </el-submenu> ``` 其中,`el-menu-item` 和 `el-submenu` 分别表示菜单项和子菜单,`index` 属性指定对应的路由路径,`router-link` 标签会自动为其添加点击事件,点击后会跳转到对应的路由页面。 3. 在路由页面中使用嵌套的 `<router-view>` 标签来显示子路由的内容。例如: ```html <template> <div> <h1>产品列表</h1> <el-menu default-active="/products/category/1" class="el-menu-vertical-demo" router > <el-menu-item v-for="category in categories" :key="category.id" :index="'/products/category/' + category.id" > {{ category.name }} </el-menu-item> </el-menu> <router-view></router-view> </div> </template> ``` 其中,`default-active` 属性指定默认选中的菜单项,`router` 属性指定使用路由模式。 通过以上步骤,即可实现无限级侧边栏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值