前言
本文所陳述的問題解決方案是技術棧基于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