Bootstrap下拉菜单内嵌daterangepicker点击日期时弹窗全部关闭问题
嘿,我明白你遇到的麻烦了——在RequireJS环境里,把daterangepicker放进Bootstrap下拉菜单后,选个日期不仅日历弹窗没了,连下拉菜单也跟着关了,不用RequireJS的时候却好好的。这问题我之前也碰到过,咱们来搞定它:
问题到底出在哪?
在RequireJS的异步模块化加载模式下,事件绑定的时机和作用域跟普通同步加载环境不一样。你原来写的$(document).on('click', 'body .dropdown-menu', function (e) { e.stopPropagation(); });虽然能阻止下拉菜单内部点击冒泡,但daterangepicker的弹窗是后续动态生成的,而且在RequireJS加载流程里,可能你的阻止冒泡代码先绑了,但daterangepicker的元素后出现,导致点击日历日期时,事件还是偷偷冒泡到了Bootstrap关闭下拉的逻辑上。
靠谱的解决方案
方案1:给daterangepicker弹窗单独加阻止冒泡
直接把阻止冒泡的目标对准daterangepicker的弹窗容器,而且要确保在daterangepicker初始化完成后绑定:
require(['jquery', 'daterangepicker'], function($) { // 先初始化daterangepicker $('#filter-expired-range').daterangepicker({ // 这里放你的配置项,比如locale、date格式之类的 }); // 阻止daterangepicker弹窗内的所有点击事件冒泡 $(document).on('click', '.daterangepicker', function(e) { e.stopPropagation(); }); // 保留原来的下拉菜单阻止冒泡逻辑 $(document).on('click', '.dropdown-menu', function(e) { e.stopPropagation(); }); });
方案2:修改Bootstrap下拉的关闭规则
Bootstrap默认点击body就会关下拉,咱们改改这个逻辑,让它无视daterangepicker相关的点击:
require(['jquery', 'bootstrap', 'daterangepicker'], function($) { // 先解绑Bootstrap默认的下拉点击事件 $(document).off('click.bs.dropdown.data-api'); // 重新绑定自定义的逻辑 $(document).on('click.bs.dropdown.data-api', function(e) { var $target = $(e.target); // 如果点击的是daterangepicker内部,或者下拉菜单内部,就不关闭下拉 if ($target.closest('.daterangepicker').length || $target.closest('.dropdown-menu').length) { return; } // 其他情况正常关闭下拉 $('.dropdown.open').removeClass('open'); }); // 初始化daterangepicker $('#filter-expired-range').daterangepicker(); });
方案3:用autoApply简化流程(适合不需要手动点确认的场景)
如果你的业务允许选完日期自动生效,可以开daterangepicker的autoApply配置,同时确保点击日期时不冒泡:
require(['jquery', 'daterangepicker'], function($) { $('#filter-expired-range').daterangepicker({ autoApply: true, // 选完日期自动关闭日历并应用 // 其他配置 }); // 单独阻止日历单元格的点击冒泡 $(document).on('click', '.daterangepicker td', function(e) { e.stopPropagation(); }); });
为啥RequireJS下才出这问题?
非RequireJS环境里脚本是同步加载的,DOM渲染和事件绑定的顺序很清晰;但RequireJS是异步加载模块,可能你的阻止冒泡代码已经绑好了,daterangepicker的弹窗元素才刚生成,导致原来的事件没覆盖到新元素。上面的方案要么确保事件能捕捉到动态生成的daterangepicker,要么直接修改Bootstrap的逻辑来适配模块化环境,都能解决问题。
内容的提问来源于stack exchange,提问作者Developer

