JavaScript小案例-树形菜单(菜单数据为数组)

news2024/11/17 1:31:15

菜单层级理论上可以无限多,因为是递归渲染。

gif演示图:
在这里插入图片描述
代码:
树形菜单.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>树形菜单-数组</title>
  <style>
    * {
      padding: 0;
      margin: 0;
      box-sizing: border-box;
      font-size: 14px;
      color: #fff;
    }

    body {
      background-color: #222;
    }

    .aside-menu {
      position: fixed;
      padding: 20px;
      width: 300px;
      height: 700px;
      background-color: #333;
      overflow: auto;
    }

    ul {
      list-style: none;
    }

    .aside-menu a {
      display: block;
      text-decoration: none;
      height: 30px;
      line-height: 30px;
    }

    .active {
      color: #00ff30;
    }

    .aside-menu a:hover {
      background-color: #727171;
    }

    [data-childs]::after {
      content: '-';
      float: right;
    }

    .expand::after {
      content: '+';
      float: right;
    }

    .notdisplay {
      display: none;
    }
  </style>
</head>

<body>
  <div class="aside-menu">
    <ul class="menuwrapper">

    </ul>
  </div>
  <script>
    // 菜单数据集合
    let menuArray = [
      {
        id: '0',//菜单id
        name: '树形菜单',//菜单名
        submenu: [//子菜单集合
          {
            id: '0',
            name: '菜单',
            submenu: [
              {
                id: '0',
                name: '菜单',
                submenu: [{
                  id: '0',
                  name: '菜单',
                  submenu: []
                },
                {
                  id: '0',
                  name: '菜单',
                  submenu: [{
                    id: '0',
                    name: '菜单',
                    submenu: []
                  }, {
                    id: '0',
                    name: '菜单',
                    submenu: []
                  }, {
                    id: '0',
                    name: '菜单',
                    submenu: []
                  }, {
                    id: '0',
                    name: '菜单',
                    submenu: []
                  },]
                },
                ]
              },
            ]
          },
        ]
      },
      {
        id: '0',
        name: '菜单',
        submenu: [
          {
            id: '0',
            name: '菜单',
            submenu: []
          },
        ]
      },
      {
        id: '0',
        name: '菜单',
        submenu: []
      }, {
        id: '0',
        name: '菜单',
        submenu: []
      }, {
        id: '0',
        name: '菜单',
        submenu: []
      }, {
        id: '0',
        name: '菜单',
        submenu: []
      }, {
        id: '0',
        name: '菜单',
        submenu: []
      }, {
        id: '0',
        name: '菜单',
        submenu: []
      }, {
        id: '0',
        name: '菜单',
        submenu: []
      }, {
        id: '0',
        name: '菜单',
        submenu: [
          {
            id: '0',
            name: '菜单',
            submenu: []
          }, {
            id: '0',
            name: '菜单',
            submenu: []
          }, {
            id: '0',
            name: '菜单',
            submenu: [{
              id: '0',
              name: '菜单',
              submenu: []
            }, {
              id: '0',
              name: '菜单',
              submenu: []
            },]
          },
        ]
      }, {
        id: '0',
        name: '菜单',
        submenu: []
      }, {
        id: '0',
        name: '菜单',
        submenu: []
      },
    ]

    /**
     * menuData-菜单数组
     * menuwrapper-当前菜单项包裹盒子
     * level-菜单层级,L0,L1,L2,...
     * paddingLeft-当前菜单的子菜单左内边距,制造树形缩进效果
     * paddingLeftIncrement-每层菜单左内边距增加值,默认20(px)
     */
    function renderMenu(menuData, menuwrapper, level = 0, paddingLeft = 0, paddingLeftIncrement = 20) {
      if (menuData && menuData.length > 0) {
        let l = level
        menuwrapper.classList.add(`L${l}`)
        menuwrapper.style.paddingLeft = `${paddingLeft}px`
        for (let i = 0; i < menuData.length; i++) {
          /** 
           * <ul class="menuwrapper">
           *  <li class="menuitem">
           *   <a href="#" data-childs="3" class="expand"><span class="active">菜单名</span>::after</a>
           *   <ul class="notdisplay">
           *    </ul>
           *  </li>
           * </ul>
           */
          const menuItem = document.createElement('li')
          menuItem.classList.add('menuitem')
          const link = document.createElement('a')
          link.href = '#'
          link.innerHTML = `<span>${menuData[i].name}</span>`
          menuItem.appendChild(link)
          menuwrapper.appendChild(menuItem)
          const submenu = menuData[i].submenu
          if (submenu.length > 0) {
            l++
            link.dataset.childs = submenu.length
            const submenuWrapper = document.createElement('ul')
            // 展开折叠图标切换、子菜单显示隐藏切换
            link.addEventListener('click', () => {
              link.classList.toggle('expand')
              link.nextElementSibling.classList.toggle('notdisplay')
            })
            paddingLeft = paddingLeftIncrement
            // 递归渲染子菜单数组
            renderMenu(submenu, submenuWrapper, l, paddingLeft)
            menuItem.appendChild(submenuWrapper)
          }
        }
      }
    }

    const menuwrapper = document.querySelector('.menuwrapper')
    // 活跃菜单
    menuwrapper.addEventListener('click', (e) => {
      if (e.target.tagName === 'A') {
        let activeLink = document.querySelector('.active')
        if (activeLink) activeLink.classList.remove('active')
        e.target.firstElementChild.classList.add('active')
      }
    })

    // 渲染
    renderMenu(menuArray, menuwrapper)
    // 释放菜单数据
    menuArray = null
  </script>
</body>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1025761.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全球南方《乡村振兴战略下传统村落文化旅游设计》许少辉八一著辉少许

全球南方《乡村振兴战略下传统村落文化旅游设计》许少辉八一著辉少许

第八章 排序

一、插入排序 不带哨兵 void InsertSort(int A[], int n){int i, j, temp;for (i1; i<n; i){if (A[i]<A[i-1]){temp A[i];for (ji-1; j>0 && A[j]>temp; --j){A[j1] A[j];}A[j1] temp;}} }带哨兵 void InsertSort(int A[], int n){int i, j;for (i2;…

微信小程序 实现滑块是矩形的slider组件

我发现大多数前端UI库都是圆形的滑块&#xff0c;而且圆形的滑块都没有紧贴进度条&#xff0c;都是超出了首尾端&#xff0c;所以亲自写一个矩形的滑块&#xff0c;我使用了微信小程序的wxs的事件通信写法&#xff0c;官方说这样写好&#xff0c;也不知道好哪里了。样式如下图&…

AWS入列CNCF基金会

7月27日&#xff0c;IT之家曾经报道&#xff0c;微软加入Linux旗下CNCF基金会&#xff0c;在这之后不到一个月的今天&#xff0c;亚马逊AWS也宣布&#xff0c;以铂金身份加入此基金会。 CNCF&#xff0c;全称Cloud Native Computing Fundation&#xff0c;该基金会旨在使得容器…

Java中Hashset存储原理底层深挖

上课老师讲了Hashset的添加元素方法&#xff0c;感觉不甚准确&#xff0c;于是下课扒一扒底层源码&#xff0c;这一看&#xff0c;霍&#xff01; 原来如此。现在小丁来捋一遍他的存储原理。 public boolean add(E e) {return map.put(e, PRESENT)null;} 可以看到PRESENT是一…

HTTPS 证书生成脚本详细讲解

前言 HTTPS证书的作用是用于保障网站的安全性。在HTTPS协议中&#xff0c;通过使用证书来实现客户端与服务器之间的认证和数据加密&#xff0c;防止中间人攻击、信息泄漏等安全问题的发生。https证书也就是SSL证书&#xff0c;我们首先要确定好需要 https 安全连接的域名&…

IMX6ULL移植篇-Linux内核源码目录分析一

一. Linux内核源码目录 之前文章对 Linux内核源码的文件做了大体的了解&#xff0c;如下&#xff1a; IMX6ULL移植篇-Linux内核源码文件表_凌肖战的博客-CSDN博客 本文具体说明 Linux内核源码的一些重要文件含义。 二. Linux内核源码中重要文件分析 1. arch 目录 这个目录…

Spring的后处理器

Spring后处理器 Spring后处理器是Spring对外开放的重要拓展点&#xff08;让我们可以用添加自己的逻辑&#xff09;&#xff0c;允许我们介入到Bean的整个实例化流程中来&#xff0c;以达到动态注册BeanDefinition&#xff08;向BeanDefitionMap中添加BeanDefition对象的过程&…

【视觉SLAM入门】8. 回环检测,词袋模型,字典,感知,召回,机器学习

"见人细过 掩匿盖覆” 1. 意义2. 做法2.1 词袋模型和字典2.1.2 感知偏差和感知变异2.1.2 词袋2.1.3 字典 2.2 匹配(相似度)计算 3. 提升 前言&#xff1a; 前端提取数据&#xff0c;后端优化数据&#xff0c;但误差会累计&#xff0c;需要回环检测构建全局一致的地图&…

数据结构与算法(C语言版)P5---栈

1、栈 1.1、栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。__进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。__栈中的数据元素遵守__后进先出&#xff08;先进后出&#xff09;__LIFO&#xf…

【C++STL基础入门】list改、查操作

文章目录 前言一、list查操作1.1 迭代器循环1.2 for_each函数 二、list改操作2.1 迭代器修改2.2 assign函数2.3 运算符 总结 前言 C标准模板库&#xff08;STL&#xff09;是C语言中非常重要的部分&#xff0c;它提供了一组通用的模板类和函数&#xff0c;用于处理常见的数据结…

利用C++开发一个迷你的英文单词录入和测试小程序-源码

接上一篇&#xff0c;有了数据库的查询&#xff0c;再把小测试的功能给补足&#xff0c;小程序的结构就出来了。 备注&#xff1a;enable_if 有更优秀的concept C 20替代品&#xff0c;C11 里面提到的any&#xff0c;variant&#xff0c;再C17 已经被纳入了标准库。这里完全可…

iOS加固保护技术:保护你的iOS应用免受恶意篡改

目录 转载&#xff1a;开始使用ipaguard 前言 下载ipa代码混淆保护工具 获取ipaguard登录码 代码混淆 文件混淆 IPA重签名与安装测试 转载&#xff1a;开始使用ipaguard 前言 iOS加固保护是直接针对ios ipa二进制文件的保护技术&#xff0c;可以对iOS APP中的可执行文件…

机器学习(17)---支持向量机(SVM)

支持向量机 一、概述1.1 介绍1.2 工作原理1.3 三层理解 二、sklearn.svm.SVC2.1 查看数据集2.2 contour函数2.3 画决策边界&#xff1a;制作网格2.4 建模画图 三、非线性情况推广3.1 查看数据集3.2 线性画图3.3 为非线性数据增加维度并绘制3D图像 四、核函数 一、概述 1.1 介绍…

记一次 mysql 数据库定时备份

环境&#xff1a;Centos 7.9 数据库&#xff1a;mysql 8.0.30 需求&#xff1a;生产环境 mysql 数据&#xff08;约670MB&#xff09;备份。其中存在大字段、longblob字段 参考博客&#xff1a;Linux环境下使用crontab实现mysql定时备份 - 知乎 一、数据库备份 1. 备份脚本。创…

Python项目Flask ipv6双栈支持改造

一、背景 Flask 是一个微型的(轻量)使用Python 语言开发的 WSGI Web 框架(一组库和模块),基于Werkzeug WSGI工具箱/库和Jinja2 模板引擎,当然,Python的WEB框架还有:Django、Tornado、Webpy,这暂且不提。 Flask使用BSD授权。 Flask也被称为microframework(微框架),F…

RFID技术在工业智能制造生产线中的应用

随着自动化和信息化的快速发展&#xff0c;工业智能制造成为制造业的重要趋势&#xff0c;在制造商的生产线上&#xff0c;准确获取和管理工艺流程等各个环节的信息至关重要&#xff0c;作为物联网感知层的核心组成部分&#xff0c;RFID技术以其非接触式、无感知的特点&#xf…

隔山打牛:金融大崩溃

当2004-2006年美联储主席格林斯潘在任期的末尾一鼓作气把联邦利率从1%拉高到5%&#xff0c;然后把美联储主席的位子交给继任者伯南克的时候&#xff0c;没有人意识到接下来将要发生何等巨变。 图&#xff1a;美国联邦利率 伯南克把利率稳定在5.3%附近的高位一年左右时间&#x…

【ArcGIS】基本概念-矢量空间分析

栅格数据与矢量数据 1.1 栅格数据 栅格图是一个规则的阵列&#xff0c;包含着一定数量的像元或者栅格 常用的栅格图格式有&#xff1a;tif&#xff0c;png&#xff0c;jpeg/jpg等 1.2 矢量数据 矢量图是由一组描述点、线、面&#xff0c;以及它们的色彩、位置的数据&#x…

无涯教程-JavaScript - AVEDEV函数

描述 AVEDEV函数返回数据点与其平均值的绝对偏差的平均值。 AVEDEV是数据集中变异性的量度。 语法 AVEDEV (number1, [number2] ...)争论 Argument描述Required/OptionalNumber11 to 255 arguments for which you want the average of the absolute deviations.Requirednum…