Bootstrap3.37头部下拉菜单jQuery逻辑转KnockoutJS绑定实现问题
问题根因
你写的jQuery事件绑定代码在模块初始化阶段就直接执行了,此时Knockout还没完成视图渲染,页面上不存在.dropdown-submenu a.dropdown-submenu-toggle、#bs-navbar-collapse-1这些目标元素,导致事件绑定没有挂载到对应节点上,点击自然没有响应。
解决方案
你可以从下面三个方案里选最适配你项目的实现:
方案1:改为事件委托绑定(改动最小,优先推荐)
直接将事件绑定到页面初始化就存在的上层节点(比如document),后续动态渲染的子节点也能触发对应事件,代码修改如下:
// 二级菜单点击事件委托绑定 $(document).on("click", '.dropdown-submenu a.dropdown-submenu-toggle', function (e) { $('.dropdown-submenu ul').removeAttr('style'); $(this).next('ul').toggle(); e.stopPropagation(); e.preventDefault(); }); // 下拉隐藏事件委托绑定 $(document).on('hidden.bs.dropdown', '#bs-navbar-collapse-1', function () { $('.navbar-nav .dropdown-submenu ul.dropdown-menu').removeAttr('style'); });
修改后代码位置不需要调整,直接替换原来的两段绑定逻辑即可。
方案2:使用Durandal生命周期钩子挂载事件
Durandal提供了viewAttached生命周期,会在视图DOM完全挂载到页面后触发,此时可以正常选中目标元素绑定事件:
首先给shell对象新增viewAttached配置,把原来的事件绑定逻辑移到这个方法里:
var shell = { activate: activate, router: router, // 新增生命周期方法 viewAttached: function() { // 原有的jQuery事件绑定逻辑挪到这里 $('.dropdown-submenu a.dropdown-submenu-toggle').on("click", function (e) { $('.dropdown-submenu ul').removeAttr('style'); $(this).next('ul').toggle(); e.stopPropagation(); e.preventDefault(); }); $('#bs-navbar-collapse-1').on('hidden.bs.dropdown', function () { $('.navbar-nav .dropdown-submenu ul.dropdown-menu').removeAttr('style'); }); } };
原来的模块初始化阶段的绑定代码直接删掉即可。
方案3:使用Knockout原生绑定(更符合KO开发规范)
完全用Knockout的能力实现交互,不需要依赖jQuery做事件绑定:
- 先修改
route构造函数,新增二级菜单状态控制逻辑:
function route(r, moduleId, name, visible, alwaysVisible, role, condition) { var self = this; // 原有逻辑保留,新增下面两个属性 self.submenuVisible = ko.observable(false); self.toggleSubmenu = function (data, e) { // 点击时先关闭所有其他二级菜单 shell.router.routes.forEach(function(routeItem) { routeItem.submenuVisible && routeItem.submenuVisible(false); }); self.submenuVisible(!self.submenuVisible()); e.stopPropagation(); e.preventDefault(); } // 原有逻辑保留 }
- 调整HTML模板的绑定逻辑:
给二级菜单的触发a标签加属性data-bind="click: toggleSubmenu",给二级菜单的ul容器加属性data-bind="visible: submenuVisible"即可。
如果需要在一级下拉隐藏时关闭所有二级菜单,可以加一段逻辑监听bootstrap的隐藏事件,把所有route的submenuVisible设为false即可。
内容的提问来源于stack exchange,提问作者lonelydev101
相关产品推荐
相关产品推荐

