angualr1.x,bootstrap/modal.js@v3

作者: 齐梓曦 | 来源:发表于2018-11-08 17:01 被阅读7次

    前言

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

    什么样的问题?

    在基于上文所述的技术栈上所做的一个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 1948559620@qq.com

    相关文章

      网友评论

        本文标题:angualr1.x,bootstrap/modal.js@v3

        本文链接:https://www.haomeiwen.com/subject/prwwxqtx.html