Element Plus/vue3 无限级导航实现

在使用element plus 时,最初要使用的就是导航组件了,官网上看到的也就是写死的一级/二级导航,那么如何设计一个无限级且动态的导航呢?毋庸置疑,递归。废话不多说,直接看代码和效果:
代码:

8784c28b7e48b0055253bc69c854d4d9.png
目录结果

SidebarItem.vue

<template>
  <el-menu-item :index="item ? item.url : ''" v-if="!item || !item.children || item.children.length === 0">
    {{ item?.menuName }}
  </el-menu-item>

  <el-sub-menu :index="item ? item.id : ''" v-else>
    <template #title>
      <span class="tab">{{ item?.menuName }}</span>
    </template>

    <div v-for="(child, index) in item?.children" :key="index">
      <template v-if="child.children && child.children.length > 0">
        <sidebar-item :key="child.id" :item="child" />
      </template>
      <el-menu-item v-else :index="child.url">
        <span class="tab sub">{{ child.menuName }}</span>
      </el-menu-item>
    </div>
  </el-sub-menu>
</template>

<script lang="ts" setup>
import { PropType, toRefs } from 'vue';
import { MenuNode } from '../../../../model/menuNode';

const props = defineProps({
  collapse: {
    type: Boolean,
    default: true
  },
  item: {
    type: Object as PropType<MenuNode>,
  },
});

const { item } = toRefs(props);
</script>

<style lang="scss"></style>

Index.vue

<div class="nav">
      <el-scrollbar class="scrollbar">
        <el-menu class="menu" @open="handleOpen" @close="handleClose" mode="horizontal" router>
          <SidebarItem v-for="route in menuList" :key="route.id" :item="route"></SidebarItem>
        </el-menu>
      </el-scrollbar>
    </div>

测试数据:

export default [
    {
        'id': '001',
        'parentId': '0',
        'menuName': '首页',
        'url': '/dashboard',
        'sortNo': 1,
        'icon': 'Aim'
    },
    {
        'id': '002',
        'parentId': '0',
        'menuName': '表格',
        'url': '/charts',
        'sortNo': 4,
        'icon': 'ArrowDownBold'
    },
    {
        'id': '0021',
        'parentId': '002',
        'menuName': '树状图',
        'url': '/charts/charts1',
        'sortNo': 4,
        'icon': 'ArrowDownBold'
    },
    {
        'id': '0022',
        'parentId': '002',
        'menuName': '饼状图',
        'url': '/charts/charts2',
        'sortNo': 4,
        'icon': 'ArrowDownBold'
    },
    {
        'id': '003',
        'parentId': '0',
        'menuName': '测试四级1',
        'url': '/dashboard',
        'menuType': 1,
        'sortNo': 2,
        'icon': 'Aim'
    },
    {
        'id': '0031',
        'parentId': '003',
        'menuName': '测试四级2',
        'url': '/dashboard',
        'menuType': 1,
        'sortNo': 2,
        'icon': 'Aim'
    },
    {
        'id': '00311',
        'parentId': '0031',
        'menuName': '测试四级3',
        'url': '/dashboard',
        'menuType': 1,
        'sortNo': 2,
        'icon': 'Aim'
    },
    {
        'id': '003111',
        'parentId': '00311',
        'menuName': '测试四级4',
        'url': '/dashboard',
        'menuType': 1,
        'sortNo': 2,
        'icon': 'Aim'
    },
];

这里需要将数组转换成树形结构,也附上代码好了(纯手工输出,有bug还望见谅):

/*
 * @Author: zzh
 * @Date: 2022-03-01 14:39:16
 * @LastEditors: zzh
 * @LastEditTime: 2022-04-10 17:13:03
 * @Description: 数据转换帮助类
 * @FilePath: \zh-admin\src\utils\dataConvert.ts
 */

import { MenuNode } from '../model/menuNode';

// 由于菜单数据并非一颗树,而是多棵树组成的数据,顾当成由树组成的数组的处理
const convertMenuArrToTree = (array: Array<MenuNode>) => {
    const rootMenus = array.filter(x => x.parentId === '0');
    const childrenMenus = array.filter(x => x.parentId !== '0');
    for (let i = 0; i < rootMenus.length; i++) {
        if (childrenMenus.find(x => x.parentId === rootMenus[i].id)) {
            rootMenus[i].children = getRootMenuChild(rootMenus[i].id, childrenMenus);
        } else {
            rootMenus[i].children = [];
        }
    }
    return rootMenus;
};

const getRootMenuChild = (id: string, childrenMenus: Array<MenuNode>): Array<MenuNode> => {
    const menus = childrenMenus.filter(x => x.parentId === id);
    for (let i = 0; i < menus.length; i++) {
        if (childrenMenus.find(x => x.parentId === menus[i].id)) {
            menus[i].children = getRootMenuChild(menus[i].id, childrenMenus);
        } else {
            menus[i].children = [];
        }
    }
    return menus;
};



export {
    convertMenuArrToTree,
};

展示结果:

af47773eb6924169c74f22b03c8a2adb.png

 

  • 15
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是使用element-plus和Vue3实现的简单计算器示例: HTML代码: ```html <div id="app"> <el-input v-model="input" placeholder="请输入数字"></el-input> <div class="btn-group"> <el-button @click="append('+')">+</el-button> <el-button @click="append('-')">-</el-button> <el-button @click="append('*')">*</el-button> <el-button @click="append('/')">/</el-button> <el-button @click="calculate">=</el-button> </div> <div class="result">{{ result }}</div> </div> ``` JavaScript代码: ```js import { createApp, ref } from 'vue' import { ElInput, ElButton } from 'element-plus' const app = createApp({ components: { ElInput, ElButton }, setup() { const input = ref('0') const result = ref('0') const operator = ref(null) const resetInput = () => { input.value = '0' operator.value = null } const append = (value) => { if (input.value === '0') { input.value = value } else { input.value += value } } const calculate = () => { const a = parseFloat(result.value) const b = parseFloat(input.value) switch (operator.value) { case '+': result.value = a + b break case '-': result.value = a - b break case '*': result.value = a * b break case '/': result.value = a / b break default: result.value = input.value } resetInput() } return { input, result, operator, resetInput, append, calculate } } }) app.mount('#app') ``` CSS代码: ```css .btn-group { display: flex; margin-top: 10px; } .el-button { flex: 1; margin-right: 10px; } .result { margin-top: 10px; font-size: 24px; } ``` 效果展示: ![效果展示](https://i.loli.net/2022/01/06/8sTzJrO9oCvGKjN.png)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值