×
文章路径: WEB前端 > JS

Bootstrap同时弹出多个模态窗口Modal时的几个问题

发表于6年前(Jun 15, 2016 10:47:49 AM)  阅读 28359  评论 2

分类: WEB前端 JS

标签: modal 相互遮盖 偏移 溢出

Bootstrap中的modal组件是使用率比较高的组件之一,可modal本身对于同一个页面同时弹出多个modal的情况支持并不是很好,有些人说应该尽量避免同时弹出多个modal,应该关闭之前的modal再弹出新的modal,确实,弹出多个modal会导致页面看起来比较混乱,但不管出于什么原因,我们经常还是会碰到需要弹出多个modal的情况。

首先,碰到的第一个问题就是如果弹出多个modal,会出现相互遮盖的情况。bootstrap对modal的弹层固定了一个z-index,笔者使用的bootstrap版本为3.3.4,z-index值为1050,不同版本可能会不同。使用相同的z-index就会导致后面的弹出层无法遮住前面的弹出层的情况。这时,我们想,如果之后每个弹出层的z-index都能递增就好了,于是,笔者增加了如下代码:

        $(document).on('hidden.bs.modal','.modal',function(e){
            $(this).css("z-index", 1050);
            dashboard.opts.modalLevel--;
        });
        $(document).on('show.bs.modal','.modal',function(e){
            $(this).css("z-index", 1050+dashboard.opts.modalLevel);
            dashboard.opts.modalLevel++;
        });
在每一个modal显示前,先获取当前弹层的数量,将z-index在1050的基础上加上弹层数量,dashboard.opts.modalLevel这个就是笔者存储弹层数量的一个变量,显示和隐藏时都分别更新这个值,这样就实现了z-index的递增。

其次,弹出第一个窗口时,窗口默认是水平居中的,接着弹出第二个,会发现窗口发生了偏移,实际上是第二个窗口被设置了padding-left:15px。笔者开始以为这时作者特意设置的,这样能显出层次感,每个新弹出的窗口相对上一个进行一定偏移,但是,笔者接着弹出第三个窗口,发现padding-left还是15px,并没有增加,于是和第二个窗口重合了。

上面的测试还是在所有modal处于同一级dom节点的情况,如果是modal里面的modal,这一偏移就会导致15px的内容被遮盖了,很不幸,笔者就是这种情况。最初,笔者在新弹出的modal的shown事件上,将padding-left值进行还原,这样勉强可用,但是会出现modal突然移动的情况,对于有些强迫症的同学可能接受不了,于是笔者进一步研究了一下源码。

modal里面有一个bodyIsOverflowing属性,字面上理解是body是否溢出窗口,是在checkScrollbar方法里面计算的:

Modal.prototype.checkScrollbar = function () {
    var fullWindowWidth = window.innerWidth
    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
      var documentElementRect = document.documentElement.getBoundingClientRect()
      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
    }
    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
    this.scrollbarWidth = this.measureScrollbar()
  }
笔者坐看右看,感觉这个值的意思好像是反了,方法里面,body的可见区域如果小于窗口的可见区域,bodyIsOverflowing值就是true,小于,不是应该没溢出吗。

adjustDialog方法对modal的padding-left和padding-right值进行了设置:

Modal.prototype.adjustDialog = function () {
    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight

    this.$element.css({
      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
    })
  }

这里可以看出来了,原来那个padding-left值15px是滚动条的宽度,padding值不是15就是0,没有其他值,跟笔者最开始想的层次结构是不相关的。第一次弹出时,笔者的document.body.clientWidth是1425,小于fullWindowWidth的1440,中间正好差个滚动条的宽度15,第二次弹出时,由于遮罩将滚动条也遮住了,document.body.clientWidth变成了1440,等于窗口的宽度,所以最后偏移了15px。笔者觉得bodyIsOverflowing是关键,body的width小于和等于window的width应该是一样的,所以笔者将代码修改成了如下:

this.bodyIsOverflowing = document.body.clientWidth <= fullWindowWidth
笔者继续查看了3.3.5的源码以及4的源码,发现计算值都还是使用的小于,可能作者确实不建议同时使用多个modal,并没有处理这种情况。

另外,如果要实现每个弹出框相对于前一个弹出框进行一定偏移,可以结合第一个问题的解决方案进行处理实现。

发表评论