angualr1.x,bootstrap/[email protected]浏览器回退操作modal遮罩未消失

前言

本文所陈述的问题解决方案是技术栈基于angualr1.x,bootstrap/[email protected]版本下,所处理的问题。(项目中遇到的一个问题,作以记录。)

什么样的问题?

在基于上文所述的技术栈上所做的一个web端项目,在测试时被提出在有弹窗的界面上调出modal层,然后点击浏览器上的回退按钮。这个时候问题就来了,页面虽然成功返回至上一页,modal层却依然存在。。。

如何解决?

在接到提出的问题后,考虑如何去解决。

1,首先,使用过bootStrap的modal.js的童鞋应该都知道其提供给我们手动操作modal层打开,关闭的api如下:

打开id为"testModal"的modal层


    $('#testModal').modal('show')

关闭modal层


    $('#testModal').modal('hide')

所以呢我的第一想法就是在点击浏览器回退按钮时,去关闭掉所有的modal那么问题不就解决了吗?

2,监听浏览器点击回退按钮触发事件


    $(document).ready(function(e) {
        if (window.history && window.history.pushState) {
            //每当处于激活状态的历史记录条目发生变化时,popstate事件就会在对应window对象上触发
            // popstate事件只会在浏览器某些行为下触发, 比如点击后退、前进按钮(或者在JavaScript中调用history.back()、history.forward()、history.go()方法).
            window.onpopstate = function () {
                // 此处进行你想要的操作
            }
        }
    }

3,浏览器的回退监听也有了,modal的关闭方法也有了,那么问题是不是就解决了呢?此处提下,每个调出的modal层都具有一个共同的class即 "modal"。一般我们会给不同的modal层赋予不同的id通过id操作modal层的展示与否。而通过class亦可同样控制。


    $(document).ready(function(e) {
        if (window.history && window.history.pushState) {
            //每当处于激活状态的历史记录条目发生变化时,popstate事件就会在对应window对象上触发
            // popstate事件只会在浏览器某些行为下触发, 比如点击后退、前进按钮(或者在JavaScript中调用history.back()、history.forward()、history.go()方法).
            window.onpopstate = function () {
                // 此处进行你想要的操作
                $(".modal").modal('hide')
            }
        }
    }

4,理论上到此就应该结束了,然鹅并木有。实际运行过程中,你会发现在执行到

$(".modal").modal('hide')

的时候,window.history亦发生了变化,原本的预期想要关闭的modal层dom结构已经不存在了!!!但是调用modal层伴随的遮罩却依然存在。。。

这个时候有小伙伴说了,那你直接将modal层的遮罩在回退触发的时间里面remove掉不就ok了吗?

是的,我也是这样想的。于是代码变成了酱紫

提一下,modal弹层调用时所附带的遮罩层所具有的class为 "modal-backdrop"


    $(document).ready(function(e) {
        if (window.history && window.history.pushState) {
            //每当处于激活状态的历史记录条目发生变化时,popstate事件就会在对应window对象上触发
            // popstate事件只会在浏览器某些行为下触发, 比如点击后退、前进按钮(或者在JavaScript中调用history.back()、history.forward()、history.go()方法).
            window.onpopstate = function () {
                // 此处进行你想要的操作
                $(".modal-backdrop").remove()
            }
        }
    }

5, 万事大吉,打完收工?那是不可能的。如上操作之后,果然如预期一般再也没有黑糊糊的一层面纱遮挡我们的实现了。but你有木有发现你的页面不能滚动了!!!我去!remove了一个遮罩怎么就不能滚动了呢?

于是乎,我想起来了源码。这个时候去看一眼源码对于modal层的展示与关闭到底做了什么操作?

相关源码如下:

modal.show()


    Modal.prototype.show = function (_relatedTarget) {
        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') // 注意这里,show()的时候给我们的页面添加了一个 "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)
        })
    }

Modal.hide()


    Modal.prototype.hide = function (e) {

        if (e) e.preventDefault()

        e = $.Event('hide.bs.modal')

        this.$element.trigger(e)

        if (!this.isShown || e.isDefaultPrevented()) return

        this.isShown = false

        this.escape()
        this.resize()

        $(document).off('focusin.bs.modal')

        this.$element
          .removeClass('in')
          .off('click.dismiss.bs.modal')
          .off('mouseup.dismiss.bs.modal')

        this.$dialog.off('mousedown.dismiss.bs.modal')

        $.support.transition && this.$element.hasClass('fade') ?
          this.$element
            .one('bsTransitionEnd', $.proxy(this.hideModal, this))
            .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
          this.hideModal() // 这里我们看到在执行hide时调用了hideModal()的方法
  }

hideModal()


    Modal.prototype.hideModal = function () {
        var that = this
        this.$element.hide()
        this.backdrop(function () {
          that.$body.removeClass('modal-open') // 清除添加在body上的类名
          that.resetAdjustments()
          that.resetScrollbar()
          that.$element.trigger('hidden.bs.modal')
        })
    }

那么这个类名有做了些什么呢?我们看一下


    .modal-open {
        overflow: hidden;
    }

没有错,就是它限制了我们的页面滚动。那么剩下的就好办了


    $(document).ready(function(e) {
        if (window.history && window.history.pushState) {
            //每当处于激活状态的历史记录条目发生变化时,popstate事件就会在对应window对象上触发
            // popstate事件只会在浏览器某些行为下触发, 比如点击后退、前进按钮(或者在JavaScript中调用history.back()、history.forward()、history.go()方法).
            window.onpopstate = function () {
                // 此处进行你想要的操作
                $("body").removeClass("modal-open")
                $(".modal-backdrop").remove()
            }
        }
    }

6, ok ...这次是真的结束了。。。纯属个人浅见。如有更好解决方案欢迎赐教。


created by 18/11/06

author by sparkc

email [email protected]

你可能感兴趣的:(angualr1.x,bootstrap/[email protected]浏览器回退操作modal遮罩未消失)