解决 Bootstrap 多个模态窗无法覆盖的问题

发布于 2023-11-19 19:26:35 字数 7721 浏览 26 评论 0

问题现象如下:

各位看官可能已经看出了问题,页面先后弹出 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">&times;</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">&times;</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">&times;</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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84960 人气
更多

推荐作者

内心激荡

文章 0 评论 0

JSmiles

文章 0 评论 0

左秋

文章 0 评论 0

迪街小绵羊

文章 0 评论 0

瞳孔里扚悲伤

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文