解决 Bootstrap 多个模态窗无法覆盖的问题
问题现象如下:
各位看官可能已经看出了问题,页面先后弹出 3 个 modal,看效果 modal 显示正确,但是遮罩都堆在第 1 个 modal 下面了,期望效果是 modal3 遮罩盖住 modal2,modal2 遮罩盖住 modal1。
解决方案
可以在 modal 显示的时候,将 modal 和遮罩设置合适的 z-index 属性,让最后打开的 modal 和遮罩显示在最上面。
具体方案是:重写 bootstrap.js 中 modal 的 show 方法,取当前所有显示状态的 modal 和遮罩, 计算所有这些元素的 z-index 属性最大值 max, 将即将显示的遮罩 z-index 属性设置为 max+10, 将即将显示的 modal 的 z-index 属性设置为 max+20
代码讲解
先创建实例代码,从 bootstrap 官网 copy 的代码基本结构,增加 3 个 modal
<!-- Modal --> <div class="modal fade" id="myModal" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">1</h4> </div> <div class="modal-body"> 我是 1 <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal1"> 打开 2 </button> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> </div> </div> </div> </div> <div class="modal fade" id="myModal1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" >2</h4> </div> <div class="modal-body"> 我是 2 <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal2"> 打开 3 </button> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> </div> </div> </div> </div> <div class="modal fade" id="myModal2" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog modal-sm" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" >3</h4> </div> <div class="modal-body"> 我是 3 </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> </div> </div> </div> </div>
分析 bootstrap 源码,版本:3.4.1;找到 modal 的 show 方法:
看源码是通过 Modal 对象设置的,往上看源码发现 Modal 是一个构造函数似得存在:
并且最终作为 modal 的构造函数:
分析到这里,我们就确定:重写 modal 构造器里的 show 方法
我们在示例程序最下面添加 js 代码,先将 Modal 取出来:
<script type="text/javascript">
+function ($) {
let Modal = $.fn.modal.Constructor; // 先将 Modal 取出来
}(jQuery);
</script>
然后将 bootstrap.js 中的 show 方法源码完整的拷贝到示例中:
拷贝完之后找到设置 backdrop 属性的匿名函数:
在匿名函数里面加上扩展代码:
// expansion part // 取当前所有显示状态的 modal 和遮罩, 计算所有这些元素的 z-index 属性最大值 max, 将即将显示的遮罩 z-index 属性设置为 max+10, 将即将显示的 modal 的 z-index 属性设置为 max+20 let $beShowDialog = that.$element; let $beShowBackDrop = that.$backdrop; let zIndexAry = $.map($(".modal:visible,.modal-backdrop:visible"), function(obj){return $(obj).css('z-index')}); let max = 1030; if (zIndexAry && zIndexAry.length > 0) { max = Math.max.apply(null, zIndexAry); } $beShowDialog.css("z-index", max + 20); $beShowBackDrop.css("z-index", max + 10);
最终效果:
核心代码:
// 修复模态框多个不能被覆盖的 bug +(function ($) { let Modal = $.fn.modal.Constructor; Modal.prototype.show = function (_relatedTarget) { // the source code copy from bootstrap.js, version = 3.4.1 var that = this; var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }); this.$element.trigger(e); if (this.isShown || e.isDefaultPrevented()) return; this.isShown = true; this.checkScrollbar(); this.setScrollbar(); this.$body.addClass('modal-open'); this.escape(); this.resize(); this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)); this.$dialog.on('mousedown.dismiss.bs.modal', function () { that.$element.one('mouseup.dismiss.bs.modal', function (e) { if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true; }); }); this.backdrop(function () { var transition = $.support.transition && that.$element.hasClass('fade'); if (!that.$element.parent().length) { that.$element.appendTo(that.$body); // don't move modals dom position } that.$element.show().scrollTop(0); that.adjustDialog(); if (transition) { that.$element[0].offsetWidth; // force reflow } that.$element.addClass('in'); that.enforceFocus(); var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }); transition ? that.$dialog // wait for modal to slide in .one('bsTransitionEnd', function () { that.$element.trigger('focus').trigger(e); }) .emulateTransitionEnd(Modal.TRANSITION_DURATION) : that.$element.trigger('focus').trigger(e); // expansion part // 取当前所有显示状态的 modal 和遮罩, 计算所有这些元素的 z-index 属性最大值 max, 将即将显示的遮罩 z-index 属性设置为 max+10, 将即将显示的 modal 的 z-index 属性设置为 max+20 let $beShowDialog = that.$element; let $beShowBackDrop = that.$backdrop; let zIndexAry = $.map($('.modal:visible,.modal-backdrop:visible'), function (obj) { return $(obj).css('z-index'); }); let max = 1030; if (zIndexAry && zIndexAry.length > 0) { max = Math.max.apply(null, zIndexAry); } $beShowDialog.css('z-index', max + 20); $beShowBackDrop.css('z-index', max + 10); }); }; })(jQuery);
将以上代码拷贝到任意页面引入的 JS 文件里面即可。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论