解决bootstrap弹出多个modal遮罩始终在第一个modal下面问题

目录

1.场景描述

2.解决方案

3.代码讲解

4.完整代码


1.场景描述

html页面先后弹出3个modal,看效果modal显示正确,但是遮罩都堆在第1个modal下面了;

期望效果:modal3遮罩盖住modal2,modal2遮罩盖住modal1

2.解决方案

可以在modal显示的时候,将modal和遮罩设置合适的z-index属性,让最后打开的modal和遮罩显示在最上面。

具体方案是:重写bootstrap.js中 modal 的show方法,取当前所有显示状态的modal和遮罩, 计算所有这些元素的z-index属性最大值max, 将即将显示的遮罩z-index属性设置为max+10, 将即将显示的modal的z-index属性设置为max+20

3.代码讲解

先创建实例代码,从bootstrap官网copy的代码基本结构,增加3个modal

<!doctype html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>Bootstrap 101 Template</title>

    <!-- Bootstrap -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">

    <!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
    <!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
    <!--[if lt IE 9]>
    <script src="https://fastly.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
    <script src="https://fastly.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
    <![endif]-->
</head>
<body>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal">
    打开1
</button>

<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" 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" tabindex="-1" 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" tabindex="-1" 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>

<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="https://fastly.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
</body>
</html>

运行之后3个modal都显示的效果是这样的

接下来分析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);

看下最终效果:

 

4.完整代码

<!doctype html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>Bootstrap 101 Template</title>

    <!-- Bootstrap -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">

    <!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
    <!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
    <!--[if lt IE 9]>
    <script src="https://fastly.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
    <script src="https://fastly.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
    <![endif]-->
</head>
<body>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal">
    打开1
</button>

<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" 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" tabindex="-1" 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" tabindex="-1" 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>

<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="https://fastly.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
<script type="text/javascript">
    +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);
</script>
</body>
</html>

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要实现多个弹出框,可以通过动态创建多个模态框的方式来实现。以下是一种实现方法: 1. 在 HTML 中添加一个按钮,用于触发弹出框: ```html <button id="btnOpenModal" class="btn btn-primary">打开模态框</button> ``` 2. 在 JavaScript 中编写代码,用于动态创建模态框: ```javascript // 模态框计数器,用于生成唯一的 ID var modalCount = 0; // 创建模态框函数 function createModal() { // 创建模态框 HTML var modalHTML = '<div id="modal' + modalCount + '" class="modal fade" tabindex="-1" role="dialog">'; modalHTML += '<div class="modal-dialog" role="document">'; modalHTML += '<div class="modal-content">'; modalHTML += '<div class="modal-header">'; modalHTML += '<h5 class="modal-title">模态框标题</h5>'; modalHTML += '<button type="button" class="close" data-dismiss="modal" aria-label="Close">'; modalHTML += '<span aria-hidden="true">×</span>'; modalHTML += '</button>'; modalHTML += '</div>'; modalHTML += '<div class="modal-body">'; modalHTML += '<p>模态框内容</p>'; modalHTML += '</div>'; modalHTML += '<div class="modal-footer">'; modalHTML += '<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>'; modalHTML += '<button type="button" class="btn btn-primary">保存</button>'; modalHTML += '</div>'; modalHTML += '</div>'; modalHTML += '</div>'; modalHTML += '</div>'; // 将模态框 HTML 添加到页面中 $('body').append(modalHTML); // 增加计数器,确保每个模态框具有唯一的 ID modalCount++; // 返回最新创建的模态框的 ID return 'modal' + (modalCount - 1); } ``` 3. 在 JavaScript 中编写代码,用于打开模态框: ```javascript // 点击按钮时打开模态框 $('#btnOpenModal').click(function () { // 创建一个新的模态框 var modalId = createModal(); // 打开新的模态框 $('#' + modalId).modal('show'); }); ``` 这样就可以通过点击按钮来打开多个模态框了。每次点击按钮时,都会动态创建一个新的模态框,并打开它。注意,这里使用了 jQuery 和 Bootstrap 的 JavaScript 插件。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值