Bootstrap 4 多级下拉菜单(Multi-Level Dropdown)Hack 实现指南:以 flask-admin 导航为例
后端【免费下载链接】flask-adminSimple and extensible administrative interface framework for Flask项目地址https://gitcode.com/gh_mirrors/fl/flask-admin点击查看免费下载本文围绕 flask-admin 仓库内置的第三方组件multi-level-dropdowns-bootstrap展开讲解如何在不修改 Bootstrap 4 官方 CSS/JS 的前提下让下拉菜单支持无限层级展开。文章既覆盖组件的完整用法基础引入、Hover 触发、事件处理也结合 flask-admin 源码说明其在后台导航菜单中的真实集成方式与工作原理读完即可在自己的 Bootstrap 4 项目中复刻同款多级菜单。背景Bootstrap 4 原生下拉为何做不到多级Bootstrap 4 的官方下拉组件dropdown.js在设计上只支持“一层下拉”点击/悬停[data-toggledropdown]元素后dropdown.js只会切换当前菜单的show类当二级菜单里再嵌套一个.dropdown时官方组件既不会在点击时阻止事件冒泡也不会在关闭时区分“子菜单是否仍处于打开状态”结果就是子菜单一点开父菜单就被关闭深层菜单永远无法稳定显示。multi-level-dropdowns-bootstrap正是针对这一缺口设计的 hack它复用 Bootstrap 官方的dropdown()方法、事件与数据结构只通过一层轻量包装就能实现“无限级”下拉且不引入任何额外 CSS 类来覆盖官方样式——正如其 README 所说“Using official HTML without adding extra CSS styles and classes, its just like native support”。该组件对应的核心文件位于仓库 flask_admin/static/vendor/multi-level-dropdowns-bootstrap/ 目录文件作用bootstrap4-dropdown-ml-hack.js核心多级下拉 hack点击触发bootstrap4-dropdown-ml-hack-hover.js带 Hover 触发版本包含 hack 鼠标悬停逻辑bootstrap4-dropdown-ml-hack-hover.css配合 Hover 使用的间距修正样式README.md官方使用说明本文分析主体基础用法一行script开启多级下拉根据 README 的 “Base” 部分多级下拉的开启方式极其简单在 jQuery 与 Bootstrap 的 JS 文件之后引入 hack 脚本即可script srchttps://raw.githubusercontent.com/dallaslu/bootstrap-4-multi-level-dropdown/master/bootstrap4-dropdown-ml-hack.js/script注意事项加载顺序必须为jquery → bootstrap含 dropdown.js→ 本 hack 脚本因为 hack 内部会读取并包装$.fn.dropdown依赖官方组件已就绪引入后无需修改任何 HTML 结构官方文档 getbootstrap.com/docs/4.4/components/dropdowns 中列出的所有功能不受影响——CSS 类、JS 方法、事件与选项均可照常使用在 flask-admin 中该脚本并非由用户手工引入而是由后台基础模板统一加载详见下文“flask-admin 的集成方式”。原理剖析hack 到底改了什么阅读仓库内的 bootstrap4-dropdown-ml-hack.js 源码可以发现它的全部逻辑只有 26 行核心是“包装官方方法 接管事件”$.fn.dropdown (function() { var $bsDropdown $.fn.dropdown; // 1. 保存官方 $.fn.dropdown return function(config) { if (typeof config string config toggle) { // 2. 拦截 toggle 调用 $(.has-child-dropdown-show).removeClass(has-child-dropdown-show); $(this).closest(.dropdown).parents(.dropdown).addClass(has-child-dropdown-show); } var ret $bsDropdown.call($(this), config); // 3. 调用官方方法完成实际开关 $(this).off(click.bs.dropdown); // 4. 关闭官方内置的 click 绑定防止重复 toggle return ret; } })(); $(function() { $(.dropdown [data-toggledropdown]).on(click, function(e) { $(this).dropdown(toggle); e.stopPropagation(); // 5. 阻止冒泡避免事件传给父级 dropdown }); $(.dropdown).on(hide.bs.dropdown, function(e) { if ($(this).is(.has-child-dropdown-show)) { // 6. 子菜单打开时阻止父菜单被隐藏 $(this).removeClass(has-child-dropdown-show); e.preventDefault(); } e.stopPropagation(); // 7. 多级模式下不再向上传播 hide 事件 }); });逐段拆解其工作机制包装$.fn.dropdown先把官方实现保存为$bsDropdown再返回新函数。这样外部调用$(...).dropdown(toggle)时仍会执行官方逻辑hack 只是在其前后追加行为。标记祖先菜单触发toggle时先清除全局的has-child-dropdown-show标记再给当前.dropdown的所有祖先.dropdown加上该标记用于记录“哪些父菜单下有正在打开的子菜单”。移除官方 click 绑定Bootstrap 官方dropdown.js会给[data-toggledropdown]绑定click.bs.dropdown内部会再次调用toggle()hack 用$(this).off(click.bs.dropdown)将其关闭避免一次点击触发两次开关导致菜单闪动。点击事件自行接管在 document ready 后统一为所有.dropdown [data-toggledropdown]绑定 click显式调用dropdown(toggle)并e.stopPropagation()——这是多级菜单最关键的一步点击子菜单按钮时事件不会冒泡到父级 dropdown 的处理器父菜单因此不会被意外关闭。拦截hide.bs.dropdown当某个 dropdown 触发隐藏事件时如果它带有has-child-dropdown-show标记说明它的子菜单还开着就preventDefault()阻止其关闭并移除标记同时stopPropagation()阻止隐藏事件继续向上传播保证深层菜单关闭时不会连坐关闭上层菜单。这套设计保证了两个核心体验点开深层子菜单时父级保持打开关闭深层子菜单时父级不受影响。Hover 触发鼠标悬停即展开README 的 “Hover” 部分提供了两种实现方式。方式一手动加样式 事件先加一行 CSS把菜单与触发元素之间的间距归零避免鼠标从按钮移向菜单时触发mouseleave而被误关.dropdown-hover-all .dropdown-menu, .dropdown-hover .dropdown-menu { margin:0 }再为指定容器绑定mouseenter/mouseleave事件用dropdown(toggle)README 建议使用toggle以获得最佳体验控制开关$(.dropdown-hover).on(mouseenter,function() { if(!$(this).hasClass(show)){ $([data-toggledropdown], this).dropdown(toggle); } }); $(.dropdown-hover).on(mouseleave,function() { if($(this).hasClass(show)){ $([data-toggledropdown], this).dropdown(toggle); } }); $(.dropdown-hover-all).on(mouseenter, .dropdown, function() { if(!$(this).hasClass(show)){ $([data-toggledropdown], this).dropdown(toggle); } }); $(.dropdown-hover-all).on(mouseleave, .dropdown, function() { if($(this).hasClass(show)){ $([data-toggledropdown], this).dropdown(toggle); } });两类选择器的区别.dropdown-hover针对单个dropdown 元素只监听其自身的鼠标进出.dropdown-hover-all针对容器内所有.dropdown利用事件委托on(mouseenter, .dropdown, ...)一次绑定、全局生效适合整条导航栏整体启用 Hover。方式二直接引入配套文件如果不想手写事件仓库已经提供了现成的组合文件README 给出的完整用法如下link relstylesheet hrefhttps://raw.githubusercontent.com/dallaslu/bootstrap-4-multi-level-dropdown/master/bootstrap4-dropdown-ml-hack-hover.css / ... div classdropdown-hover-all !-- .dropdown elements -- /div div classdropdown dropdown-hover !-- toggle and menu elements -- /div ... script srchttps://raw.githubusercontent.com/dallaslu/bootstrap-4-multi-level-dropdown/master/bootstrap4-dropdown-ml-hack-hover.js/script对照仓库文件可以确认bootstrap4-dropdown-ml-hack-hover.css 内容与 README 中的样式完全一致margin:0一条规则bootstrap4-dropdown-ml-hack-hover.js 前 26 行与bootstrap4-dropdown-ml-hack.js完全相同其后追加了.dropdown-hover/.dropdown-hover-all的鼠标事件绑定。因此若只需点击触发引入bootstrap4-dropdown-ml-hack.js一个文件即可需要 Hover 时则换成-hover后缀的 JS CSS 组合。flask-admin 的集成方式后台导航栏的多级菜单flask-admin 使用 Bootstrap 4 渲染整个管理后台界面其左侧顶部导航由Admin.menu()生成的菜单树驱动。为了让分类category可以嵌套为多级下拉仓库直接内置了该 hack 组件。1. 模板层统一加载 hack 脚本所有 Bootstrap 4 后台页面共用的基础模板 flask_admin/templates/bootstrap4/admin/base.html 在tail_js块中按顺序加载脚本见 base.html 第 81-98 行script src{{ admin_static.url(filenamevendor/jquery.min.js, v3.5.1) }} .../script script src{{ admin_static.url(filenamebootstrap/bootstrap4/js/bootstrap.min.js, v4.6.2) }} .../script script src{{ admin_static.url(filenamevendor/bootstrap4/util.js, v4.3.1) }} .../script script src{{ admin_static.url(filenamevendor/bootstrap4/dropdown.js, v4.3.1) }} .../script script src{{ admin_static.url(filenamevendor/multi-level-dropdowns-bootstrap/bootstrap4-dropdown-ml-hack.js) }} .../script可以观察到 flask-admin 在加载顺序上的刻意安排jquery.min.jsv3.5.1与bootstrap.min.jsv4.6.2在前之后是官方util.js与dropdown.jsv4.3.1——dropdown.js是 hack 包装的目标对象必须先就位最后才是bootstrap4-dropdown-ml-hack.js且未启用 Hover 版本即后台菜单默认使用“点击展开”交互。这正好印证了 README 中“Just add js after jquery and bootstrap js files”的要求hack 脚本必须后于官方组件加载。2. 菜单渲染递归生成嵌套.dropdown后台菜单由 flask_admin/templates/bootstrap4/admin/layout.html 中的menu()宏渲染见 layout.html 第 21-83 行。其关键逻辑是递归遇到is_category()的菜单项时渲染一个li classdropdown内部a>{%- if child.is_category() -%} {{ menu(menu_root[child]) }} {% else %} ...渲染普通菜单项... {%- endif -%}最终 DOM 形如li classdropdown a classdropdown-toggle nav-link>class SubMenuCategory(MenuCategory): def __init__(self, *args: str, **kwargs: t.Any) - None: super().__init__(*args, **kwargs) self.class_name dropdown-submenu droprightMenuDividermenu.py 第 186-203 行渲染为dropdown-divider分隔线get_url()返回None用于在菜单中插入视觉分隔。在 layout.html 第 37-41 行 中渲染宏还会依据class_name是否包含dropdown-submenu来决定显示“右箭头”还是“下箭头”图标说明SubMenuCategory的dropright类正是多级菜单“向右弹出”视觉语义的来源。与 Bootstrap 官方功能的兼容性README 特别强调官方文档中列出的所有dropdown 能力均不受 hack 影响可以放心混用CSS 类.dropdown-menu-right、.dropdown-header、.dropdown-divider、.disabled等官方类照常生效JS 方法toggle、show、hide、update等方法仍由官方实现执行hack 只是在toggle前后附加了祖先标记逻辑事件show.bs.dropdown、shown.bs.dropdown、hide.bs.dropdown、hidden.bs.dropdown等官方事件照常触发hack 仅额外监听hide.bs.dropdown做保护性拦截选项如offset、flip、boundary、reference、display等 Popper.js 相关选项不受影响。其设计哲学是“只增加行为、不改写行为”——从 bootstrap4-dropdown-ml-hack.js 源码可以看到hack 全程保留了对官方$bsDropdown的调用未替换官方实现也未新增任何覆盖官方样式的 CSS。兼容性验证与使用建议README 给出的官方 Demo 基于Bootstrap v4.4.1验证可用flask-admin 在 base.html 中同时加载了bootstrap.min.jsv4.6.2与dropdown.jsv4.3.1从源码结构与官方 README 声明可以推断该 hack 与 Bootstrap 4 系列版本均能协同工作点击版 vs Hover 版桌面端管理后台若追求效率可考虑 Hover 版引入-hover后缀的两个文件但需注意 README 中“减少间距以避免误触发 mouseleave”的 CSS 提示移动端触屏场景下点击版更稳妥加载顺序务必确保 hack 脚本在 jQuery 与官方 dropdown 组件之后加载否则包装$.fn.dropdown时会拿到未定义的实现若在 flask-admin 之外的项目中独立使用直接参照上文“基础用法”与“Hover 触发”两节引入仓库 flask_admin/static/vendor/multi-level-dropdowns-bootstrap/ 中的对应文件即可无需依赖 flask-admin 本身。小结multi-level-dropdowns-bootstrap用不到 30 行的轻量 hack为 Bootstrap 4 补上了官方缺失的“无限级下拉”能力且保持了对官方组件的高度兼容。在 flask-admin 中它通过与SubMenuCategory/MenuDivider菜单模型、layout.html递归渲染宏的配合让后台导航得以支持多级分类组织。理解其“包装$.fn.dropdown、接管 click、拦截hide.bs.dropdown”的三段式原理后你既可以直接复用仓库文件也能在遇到类似交互需求时举一反三。赞分享后端【免费下载链接】flask-adminSimple and extensible administrative interface framework for Flask项目地址https://gitcode.com/gh_mirrors/fl/flask-admin点击查看免费下载相关推荐Ant Design Blazor Dropdown 多级菜单实现指南Dropdown 与 SubMenu 联动的级联下拉菜单Ant Design Blazor Dropdown 多级菜单实现指南Dropdown 与 SubMenu 联动的级联下拉菜单 在 Ant Design Bl前端UI组件设计系统Ant Design Dropdown 多级菜单SubMenu实战指南在 React 下拉菜单中实现层级嵌套Ant Design Dropdown 多级菜单SubMenu实战指南在 React 下拉菜单中实现层级嵌套 本篇技术指南以 Ant Design 仓库中UI组件前端设计系统Brython 导航菜单实战指南用 browser.widgets.menu 构建横向导航栏与多级下拉子菜单Brython 导航菜单实战指南用 browser.widgets.menu 构建横向导航栏与多级下拉子菜单 本文是 Brython运行在浏览器中的 Pyt编程语言语言运行时编译器前端上一篇5分钟快速上手Arduino ESP32物联网开发的终极解决方案下一篇dijo视图模式完全指南Day模式和Week模式的数据可视化技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

NAudio.MacOS 使用 Core Audio HAL 播放音频文件(CoreAudioPlayer 完整实战指南)

NAudio.MacOS 使用 Core Audio HAL 播放音频文件(CoreAudioPlayer 完整实战指南)

音视频音频处理 【免费下载链接】NAudio Audio and MIDI library for .NET 项目地址: https://gitcode.com/gh_mirrors/na/NAudio 点击查看 免费下载 本篇指南基于 NAudio 仓库中的 PlayAudioFileMacOS.md 文档展开,系统讲解在 macOS 上通过 NAudio.Mac…

2026/10/10 8:20:51 阅读更多 →
Pony 编译器 0.39.1 版本修复详解:类型参数引用、Windows 管道与部分函数字面量推断

Pony 编译器 0.39.1 版本修复详解:类型参数引用、Windows 管道与部分函数字面量推断

编程语言编译器语言运行时 【免费下载链接】ponyc Pony is an open-source, actor-model, capabilities-secure, high performance programming language 项目地址: https://gitcode.com/gh_mirrors/po/ponyc 点击查看 免费下载 本篇文章围绕 Pony 语言编译器 pony…

2026/10/10 8:20:51 阅读更多 →
Zotero PDF2zh 翻译服务 extraData 额外字段配置完全指南:从插件传参到 Server 底层执行机制

Zotero PDF2zh 翻译服务 extraData 额外字段配置完全指南:从插件传参到 Server 底层执行机制

人工智能AI 应用 【免费下载链接】zotero-pdf2zh PDF2zh for Zotero | Zotero PDF中文翻译插件 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-pdf2zh 点击查看 免费下载 在 Zotero PDF2zh 中,每个 LLM 翻译服务(OpenAI、DeepSeek、O…

2026/10/10 8:20:51 阅读更多 →

最新新闻

基于 GSAP 重建 Aura 流体拖拽交互演示:从 Prompt 到源码级实现指南

基于 GSAP 重建 Aura 流体拖拽交互演示:从 Prompt 到源码级实现指南

【免费下载链接】Skills Agent skills for designers and builders using Codex, Claude, Cursor, and other AI coding agents 项目地址: https://gitcode.com/gh_mirrors/skills48/Skills 点击查看 免费下载 导读 本文以仓库中 gsap 技能 的演示提示词文档 PROM…

2026/10/10 9:06:46 阅读更多 →
Liunx网络编程:网络基础

Liunx网络编程:网络基础

文章目录一文搞懂网络层:IP、子网、路由,像送快递一样简单!1 网络层到底是什么1.1 核心定位:互联网的快递调度中心1.2 网络层的六大核心职责2 IP报文头:数据包的配送清单2.1 IPv4首部字段详解2.2 冷知识:分…

2026/10/10 9:06:46 阅读更多 →
2026年跨境电商还赚钱吗?这5个新兴蓝海平台流量红利期刚开,新手避开亚马逊内卷的实操复盘

2026年跨境电商还赚钱吗?这5个新兴蓝海平台流量红利期刚开,新手避开亚马逊内卷的实操复盘

进入2026年下半年,跨境出口电商的底层逻辑已经发生变化。单纯依赖亚马逊这类成熟平台,新卖家面临的不仅是流量成本攀升,还有存量竞争带来的利润压缩。从行业数据与第三方服务商的公开反馈来看,平台型生意的机会正在从中心化市场向…

2026/10/10 9:06:46 阅读更多 →
【单片机毕业设计】【mcu-1379】基于STM32的智能环境监测与语音播报系统

【单片机毕业设计】【mcu-1379】基于STM32的智能环境监测与语音播报系统

​ 项目编号:mcu-1379 单片机类型:STM32F103C8T6 具体功能: 1、通过DHT11监测当前环境温湿度; 2、通过通过OLED显示测量的数据; 3、通过按键按下播报当前环境的温湿度; 4、通过蓝牙ECB02将数据传输到手机端…

2026/10/10 9:06:46 阅读更多 →
智慧城市管理中心平台实战:SpringBoot + RabbitMQ + WebSocket

智慧城市管理中心平台实战:SpringBoot + RabbitMQ + WebSocket

1. 先说清楚这是个什么东西这段时间总有人私信问我“智慧城市管理中心平台”到底是个什么样的项目,能不能拿来做毕业设计或者转行练手。我干脆把实际开发中沉淀下来的这套东西完整梳理一遍。它不是那种PPT里的智慧城市,而是一个能真正跑起来的城市治理业…

2026/10/10 9:06:46 阅读更多 →
Java SpringBoot宠物领养系统设计与实现:从CRUD到业务状态机

Java SpringBoot宠物领养系统设计与实现:从CRUD到业务状态机

1. 项目概述与核心价值做毕业设计或者接外包项目时,我一直觉得“宠物领养”这个方向被低估了。表面上看它是一个普通的CRUD管理系统,但实际上它承载了真实业务场景中非常典型的双向信息匹配、流程审批和多角色权限控制,从技术锻炼的角度来看&…

2026/10/10 9:05:45 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →