动态创建Bootstrap 4多级下拉菜单时$(this)点击事件失效
动态生成Bootstrap 4多级下拉菜单的点击事件失效问题
尝试实现Bootstrap 4多级下拉菜单,硬编码版本可正常工作,但动态生成菜单后,子菜单的点击事件无法为其添加show类,导致子菜单无法展开。
CSS 代码
.dropdown-submenu-new { position: relative; } .dropdown-submenu-new a::after { transform: rotate(-90deg); position: absolute; right: 6px; top: .8em; } .dropdown-submenu-new .dropdown-menu { top: 0; left: 100%; margin-left: .1rem; margin-right: .1rem; }
HTML 代码
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous"> <div class="collapse navbar-collapse" id="navbarNavDropdown"> </div>
原始JavaScript代码
$(document).ready(function () { var data = [ { "title": "Home", "child": null }, { "title": "Dropdown link", "child": [ { "title": "Action", "child": null }, { "title": "Another Action", "child": null }, { "title": "Submenu", "child": [{ "title": "Submenu action", "child": null }, { "title": "Another submenu action", "child": null }, { "title": "Subsubmenu", "child": [{ "title": "Subsubmenu action", "child": null }, { "title": "Another subsubmenu action", "child": null } ] }, { "title": "Second subsubmenu", "child": [{ "title": "Subsubmenu action", "child": null }, { "title": "Another subsubmenu action", "child": null }] } ] } ] } ]; var list_html = "<ul class='navbar-nav'>"; var li_class = "nav-item"; var a_class = "nav-link"; var a_props = ""; for (var i = 0; i < data.length; i++) { //if (i == 0) // li_class += " active"; if (data[i].child != null) { li_class += " dropdown"; a_class += " dropdown-toggle"; a_props = " data-toggle='dropdown' id='navbarDropdownMenuLink'"; } list_html += "<li class='" + li_class + "'><a class='" + a_class + "'" + a_props + ">" + data[i].title + "</a>"; if (data[i].child != null) { list_html += CreateDynamicList(data[i], true); } list_html += "</li>"; } list_html += "</ul>"; console.log(list_html); $("#navbarNavDropdown").html(list_html); $('.dropdown-menu-new a.dropdown-toggle').on('click', function (e) { console.log("here"); console.log($(this)); if (!$(this).next().hasClass('show')) { $(this).parents('.dropdown-menu-new').first().find('.show').removeClass('show'); } var $subMenu = $(this).next('.dropdown-menu-new'); $subMenu.toggleClass('show'); $(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function (e) { $('.dropdown-submenu-new .show').removeClass('show'); }); return false; }); }); // end document ready function CreateDynamicList(data, isMainFunction) { var idText = ""; if (isMainFunction) idText += " aria-labelledby='navbarDropdownMenuLink'"; var list_html = "<ul class='dropdown-menu-new'" + idText + ">"; //console.log(data); //console.log(data.child); if (data.child != null) for (var i = 0; i < data.child.length; i++) { //if child has no child then else if (data.child[i].child == null) list_html += "<li><a class='dropdown-item'>" + data.child[i].title + "</a></li>"; else list_html += "<li class='dropdown-submenu-new'><a class='dropdown-item dropdown-toggle'>" + data.child[i].title + "</a>" + (data.child != null ? CreateDynamicList(data.child[i], false) : "") + "</li>"; console.log("loop: " + data.child[i].title); } else list_html += "<li><a class='dropdown-item'>" + data.title + "</a></li>"; list_html += "</ul>"; //console.log(list_html); return list_html; }
问题分析
- 事件绑定方式错误:动态生成的元素无法通过直接绑定事件触发,因为绑定事件时元素还未存在于DOM中。
- 类名不匹配:CSS中定义的类是
.dropdown-submenu,但JS生成的子菜单项类是dropdown-submenu-new,导致样式失效;同时子菜单的dropdown-menu-new未包含Bootstrap原生的dropdown-menu类,缺失基础下拉样式。 - 变量未重置:循环生成顶级菜单时,
li_class、a_class等变量在第一次添加dropdown类后未重置,导致后续所有菜单项都被错误添加下拉类。 - $(this)指向异常:事件绑定无效导致
this无法正确指向当前点击元素,无法输出相关信息。
修复方案
1. 改为事件委托绑定事件
将事件绑定到静态父元素#navbarNavDropdown上,确保动态生成的元素能触发事件:
// 替换原事件绑定代码 $('#navbarNavDropdown').on('click', '.dropdown-menu-new a.dropdown-toggle', function(e) { e.stopPropagation(); console.log($(this)); if (!$(this).next().hasClass('show')) { $(this).parents('.dropdown-menu').first().find('.show').removeClass('show'); } var $subMenu = $(this).next('.dropdown-menu'); $subMenu.toggleClass('show'); $(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function(e) { $('.dropdown-submenu-new .show').removeClass('show'); }); return false; });
2. 统一类名并补充Bootstrap原生类
- 保持CSS选择器与JS生成的类名一致(已在上方CSS代码中修正为
dropdown-submenu-new) - 生成子菜单时,将
dropdown-menu-new改为dropdown-menu dropdown-menu-new,继承Bootstrap的下拉菜单基础样式:
// 修改CreateDynamicList函数中的菜单类定义 var list_html = "<ul class='dropdown-menu dropdown-menu-new'" + idText + ">";
3. 重置循环变量避免类名污染
在每次循环顶级菜单项时,重置li_class、a_class、a_props,并给ID添加索引后缀避免重复:
// 替换原循环代码 for (var i = 0; i < data.length; i++) { // 每次循环重置变量 let li_class = "nav-item"; let a_class = "nav-link"; let a_props = ""; //if (i == 0) // li_class += " active"; if (data[i].child != null) { li_class += " dropdown"; a_class += " dropdown-toggle"; a_props = " data-toggle='dropdown' id='navbarDropdownMenuLink-" + i + "'"; } list_html += "<li class='" + li_class + "'><a class='" + a_class + "'" + a_props + ">" + data[i].title + "</a>"; if (data[i].child != null) { list_html += CreateDynamicList(data[i], true); } list_html += "</li>"; }
4. 修正子菜单调用逻辑
移除冗余的判断条件,直接调用子菜单生成函数:
// 修改CreateDynamicList中的else分支 else list_html += "<li class='dropdown-submenu-new'><a class='dropdown-item dropdown-toggle'>" + data.child[i].title + "</a>" + CreateDynamicList(data.child[i], false) + "</li>";
最终效果
修复后,动态生成的多级下拉菜单可以正常展开/收起,点击事件能正确为子菜单添加show类,样式也能正常渲染。
内容的提问来源于stack exchange,提问作者Samra
相关产品推荐
相关产品推荐

