element-plus动态渲染el-menu(vue3)

 样式如上

需要typescript,vue3环境下运行

需要下载依赖如下

npm install sass-loader node-sass --save-dev

npm install element-plus --save

npm install view-ui-plus@1.3.1 --save



main.ts中
import 'view-ui-plus/dist/styles/viewuiplus.css'

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'


app.use(ElementPlus)

 需要scss以及,element-plus

<template>
  <div class="sidebar">
    <el-menu :default-active="activeIndex" class="menu" active-text-color="#FFFFFF" background-color="#060E83"
      text-color="#fff" :unique-opened="true" router @select="handleSelect" @close="menuClose" @open="menuOpen">
      <template v-for="menus in ItemList" :key="menus">
        <el-sub-menu :key="menus.menuId" :index="menus.index" v-if="menus.childs">
          <template #title>
            <img :src="menus.icon" alt="" style="margin-right: 16px;width: 22px;height: 22px;">
            <span>{{ menus.title }}</span>
          </template>
          <el-timeline style="box-sizing: border-box;padding-left: 20px;">
            <el-timeline-item v-for="(childvl, ci) in menus.childs" :key="ci" center @click="changeColor">
              <!-- {{ activity.content }} -->
              <el-menu-item :index="childvl.index" :key="ci" style="margin-bottom:10px;">{{
                childvl.title
              }}</el-menu-item>
            </el-timeline-item>
          </el-timeline>
        </el-sub-menu>
        <el-menu-item :index="menus.index" v-else style="margin-bottom:10px;">
          <img :src="menus.icon" alt="" style="margin-right: 16px;">
          <span>{{ menus.title }}</span>
        </el-menu-item>
      </template>
    </el-menu>
  </div>
</template>

<script lang="ts" setup>
import getData from "@/assets/json/st_classlist.json";
import { ref, onMounted } from "vue";
const ItemList: any = ref([])
const activeIndex = ref('')
const handleSelect = (key: any) => {
  activeIndex.value = key
}
function addRouterIndex() {
  setTimeout(() => {
    const childrenArray = ItemList.value.map((item: any) => {
      return item.childs;
    });
    //用来存放child里不为null的值
    let intChild = []
    intChild = childrenArray.filter(function (val: any) {
      return val
    });
    //把intChild中的所有数组拼接起来
    const flattenedArray = intChild.reduce((acc: any[], cur: any) => {
      return acc.concat(cur);
    }, []);
    //获取该路由所对应的下标
    const index = flattenedArray.findIndex((person: { index: string; }) => person.index === activeIndex.value);
    let nodes = document.querySelectorAll('.el-timeline-item__node')[index] as HTMLElement
    if (nodes) {
      nodes.style.background = "#fff"
      nodes.style.transition = "0.5s"
    }
  }, 100);
}
const popstate = () => {
  activeIndex.value = location.hash.split("/")[1]
  addRouterIndex()
}
const changeColor = () => {
  addRouterIndex()
}
const menuClose = () => {
  addRouterIndex()
}
const menuOpen = () => {
  addRouterIndex()
}
onMounted(() => {
  // console.log(getData.data);
  ItemList.value = getData.data
  popstate()
  window.addEventListener('popstate', popstate, false);
  addRouterIndex()
  console.log(ItemList.value);
})
</script>

<style scoped lang="scss">
.sidebar {
  height: calc(100vh - 76px);
  box-shadow: 2px 0px 6px 0px rgba(0, 0, 0, 0.1);

  .menu {
    border-right: unset;
    height: 100%;
    width: 240px;
    font-size: 16px;

    .el-sub-menu {
      width: 224px;
      height: auto;
      border-radius: 8px;
      margin: auto;
    }

    ::v-deep .el-sub-menu__title {
      font-size: 16px;
    }

    .el-menu-item {
      // width: 224px;
      height: 50px;
      border-radius: 8px;
      margin: auto;
      font-size: 16px;
    }

    .is-active {
      background: rgba(94, 103, 246, 0.3);
    }

    .logo {
      height: 50px;
      line-height: 50px;
      padding: 0 10px;
      overflow: hidden;

      img {
        vertical-align: middle;
        margin-left: 6px;
      }

      span {
        font-weight: bold;
        font-size: 16px;
      }
    }
  }

  .menu:not(.el-menu--collapse) {
    width: 240px;
  }
}

::v-deep .el-sub-menu .el-menu-item {
  min-width: 0;
}

::v-deep .el-timeline-item__wrapper {
  top: 0px !important;
  height: 49px;
}

::v-deep .el-timeline-item__node {
  background: #2B329A;
}

.el-timeline {
  --el-timeline-node-color: #2B329A;
}

.el-active-fff {
  background: #fff;
}

::v-deep .el-timeline-item__wrapper {
  height: 40px;
}

.sidebar .menu[data-v-0f7446ba]:not(.el-menu--collapse) {
  box-sizing: border-box;
  padding-top: 20px;
}
</style>

下面是JSON文件内容

{
    "code": 200,
    "message": "操作成功",
    "data": [
        {
            "index": "ceshione",
            "icon": "https://img.icons8.com/3d-fluency/2x/fingerprint.png%202x,%20https://img.icons8.com/3d-fluency/1x/fingerprint.png",
            "title": "测试",
            "menuId": "1082",
            "component": null,
            "childs": [
                {
                    "index": "ceshitwo",
                    "icon": "#",
                    "title": "测试",
                    "menuId": "1087",
                    "component": null,
                    "childs": null
                },
                {
                    "index": "ceshithree",
                    "icon": "#",
                    "title": "测试",
                    "menuId": "1088",
                    "component": null,
                    "childs": null
                }
            ]
        },
        {
            "index": "ceshifore",
            "icon": "https://img.icons8.com/3d-fluency/2x/fingerprint.png%202x,%20https://img.icons8.com/3d-fluency/1x/fingerprint.png",
            "title": "测试",
            "menuId": "1083",
            "component": null,
            "childs": [
                {
                    "index": "ceshifive",
                    "icon": "#",
                    "title": "测试",
                    "menuId": "1089",
                    "component": null,
                    "childs": null
                }
            ]
        },
        {
            "index": "",
            "icon": "https://img.icons8.com/3d-fluency/2x/fingerprint.png%202x,%20https://img.icons8.com/3d-fluency/1x/fingerprint.png",
            "title": "测试",
            "menuId": "1084",
            "component": null,
            "childs": [
                {
                    "index": "ceshisix",
                    "icon": "#",
                    "title": "测试",
                    "menuId": "1001",
                    "component": null,
                    "childs": null
                }
            ]
        },
        {
            "index": "#",
            "icon": "https://img.icons8.com/3d-fluency/2x/fingerprint.png%202x,%20https://img.icons8.com/3d-fluency/1x/fingerprint.png",
            "title": "测试",
            "menuId": "1086",
            "component": null,
            "childs": [
                {
                    "index": "ceshieight",
                    "icon": "#",
                    "title": "测试",
                    "menuId": "1089",
                    "component": null,
                    "childs": null
                }
            ]
        }
    ]
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值