前面的話
在 Bootstrap 框架中把模態彈出框統一稱為 Modal。這種彈出框效果在大多數 Web 網站的交互中都可見。比如點擊一個按鈕彈出一個框,彈出的框可能是一段文件描述,也可能帶有按鈕操作,也有可能彈出的是一張圖片。本文將詳細介紹Bootstrap模態彈出框
結構分析
Bootstrap框架中的模態彈出框,分別運用了“modal”、“modal-dialog”和“modal-content”樣式,而彈出窗真正的內容都放置在“modal-content”中,其主要又包括三個部分:
☑ 彈出框頭部,一般使用“modal-header”表示,主要包括標題和關閉按鈕
☑ 彈出框主體,一般使用“modal-body”表示,彈出框的主要內容
☑ 彈出框腳部,一般使用“modal-footer”表示,主要放置操作按鈕
<div class="modal show"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title">模態彈出窗標題</h4> </div> <div class="modal-body"> <p>模態彈出窗主體內容</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">關閉</button> <button type="button" class="btn btn-primary">保存</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div><!-- /.modal -->
對于彈窗而言,modal-content是樣式的關鍵。主要設置了彈窗的邊框、邊距、背景色和陰影等樣式
.modal-content { position: relative; background-color: #fff; -webkit-background-clip: padding-box; background-clip: padding-box; border: 1px solid #999; border: 1px solid rgba(0, 0, 0, .2); border-radius: 6px; outline: 0; -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5); box-shadow: 0 3px 9px rgba(0, 0, 0, .5); }
除此之外,modal-content中的modal-header、modal-body和modal-footer三個部分樣式設置如下
.modal-header { min-height: 16.42857143px; padding: 15px; border-bottom: 1px solid #e5e5e5; } .modal-header .close { margin-top: -2px; } .modal-title { margin: 0; line-height: 1.42857143; } .modal-body { position: relative; padding: 15px; } .modal-footer { padding: 15px; text-align: right; border-top: 1px solid #e5e5e5; }
這三個部分主要控制一些間距的樣式。而modal-footer都是用來放置按鈕,所以底部還對包含的按鈕做了一定的樣式處理
.modal-footer .btn + .btn { margin-bottom: 0; margin-left: 5px; } .modal-footer .btn-group .btn + .btn { margin-left: -1px; } .modal-footer .btn-block + .btn-block { margin-left: 0; }
觸發方式
眾所周知,模態彈出窗在頁面加載完成時,是被隱藏在頁面中的,只有通過一定的動作(事件)才能觸發模態彈出窗的顯示。在Bootstrap框架中實現方法有2種
在介紹觸發方式之前,首先要說明.show和.fade這兩個方法。只有模態彈出窗默認是隱藏的,才能觸發其顯示
.fade { opacity: 0; -webkit-transition: opacity .15s linear; -o-transition: opacity .15s linear; transition: opacity .15s linear; } .show { display: block!important; }
【方法一】
模態彈出窗聲明,只需要自定義兩個必要的屬性:data-toggle和data-target(bootstrap中聲明式觸發方法一般依賴于這些自定義的data-xxx 屬性。比如data-toggle="" 或者 data-dismiss="")
data-toggle必須設置為modal(toggle中文翻譯過來就是觸發器);
data-target可以設置為CSS的選擇符,也可以設置為模態彈出窗的ID值,一般情況設置為模態彈出窗的ID值,因為ID值是唯一的值
<!-- 觸發模態彈出窗的元素 --> <button type="button" data-toggle="modal" data-target="#mymodal" class="btn btn-primary">點擊</button> <!-- 模態彈出窗 --> <div class="modal fade" id="mymodal"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title">模態彈出窗標題</h4> </div> <div class="modal-body"> <p>模態彈出窗主體內容</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">關閉</button> <button type="button" class="btn btn-primary">保存</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div><!-- /.modal -->
【方法二】
觸發模態彈出窗也可以是一個鏈接<a>元素,那么可以使用鏈接元素自帶的href屬性替代data-target屬性
不過建議還是使用統一使用data-target的方式來觸發
<!-- 觸發模態彈出窗的元素 --> <a data-toggle="modal" href="#mymodal" class=" btn btn-primary" >點擊</a> <!-- 模態彈出窗 --> <div class="modal fade" id="mymodal"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title">模態彈出窗標題</h4> </div> <div class="modal-body"> <p>模態彈出窗主體內容</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">關閉</button> <button type="button" class="btn btn-primary">保存</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div><!-- /.modal -->
尺寸
Bootstrap框架為模態彈出窗提供了不同尺寸,一個是大尺寸樣式“modal-lg”,另一個是小尺寸樣式“modal-sm”。其結構上稍做調整
[注意].bs-example-modal-lg和.bs-example-modal-sm是自定義的名稱,而非必須
<!-- 大尺寸模態彈出窗 --> <div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true"> <div class="modal-dialog modal-lg"> <div class="modal-content"> ... </div> </div> </div> <!-- 小尺寸模態彈出窗 --> <div class="modal fade bs-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true"> <div class="modal-dialog modal-sm"> <div class="modal-content"> ... </div> </div> </div>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target=".bs-example-modal-lg">大尺寸</button> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal">默認尺寸</button> <button type="button" class="btn btn-primary" data-toggle="modal" data-target=".bs-example-modal-sm">小尺寸</button> <div class="modal fade" id="myModal"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-body"> <p>小火柴的藍色理想</p> </div> </div> </div> </div> <div class="modal fade bs-example-modal-lg"> <div class="modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-body"> <p>小火柴的藍色理想</p> </div> </div> </div> </div> <div class="modal fade bs-example-modal-sm"> <div class="modal-dialog modal-sm"> <div class="modal-content"> <div class="modal-body"> <p>小火柴的藍色理想</p> </div> </div> </div> </div>
CSS解析
bootstrap中的“模態彈出框”有以下幾個特點:
1、模態彈出窗是固定在瀏覽器中的。
2、單擊右側全屏按鈕,在全屏狀態下,模態彈出窗寬度是自適應的,而且modal-dialog水平居中。
3、當瀏覽器視窗大于768px時,模態彈出窗的寬度為600px
4、模態彈出窗的背景常常有一個透明的蒙層效果
5、觸發彈窗時,彈窗是從上到下、逐漸浮現到頁面前的
【固定在瀏覽器實現】
.modal { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1050; display: none; overflow: hidden; -webkit-overflow-scrolling: touch; outline: 0; }
【水平居中實現】
.modal-dialog { position: relative; width: auto; margin: 10px; }
【當瀏覽器視窗大于768px時,模態彈出窗的寬度為600px實現】
@media (min-width: 768px) { .modal-dialog { width: 600px; margin: 30px auto; } .modal-content { -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); box-shadow: 0 5px 15px rgba(0, 0, 0, .5); } .modal-sm { width: 300px; } }
【蒙版】
彈窗彈出時為 <body>
元素添加 .modal-open
類,從而覆蓋頁面默認的滾動行為,并且還會自動生成一個 .modal-backdrop
元素用于提供一個可點擊的區域,點擊此區域就即可關閉模態框
.modal-open { overflow: hidden; }
.modal-backdrop { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1040; background-color: #000; }
給其添加了一個過渡動畫,從fade到in,把opacity值從0變成了0.5
.modal-backdrop.fade { filter: alpha(opacity=0); opacity: 0; } .modal-backdrop.in { filter: alpha(opacity=50); opacity: .5; }
【動畫效果】
彈窗的動畫內容是從-25%的top值位置到top:0的位置
.modal.fade .modal-dialog { -webkit-transition: -webkit-transform .3s ease-out; -o-transition: -o-transform .3s ease-out; transition: transform .3s ease-out; -webkit-transform: translate3d(0, -25%, 0); -o-transform: translate3d(0, -25%, 0); transform: translate3d(0, -25%, 0); } .modal.in .modal-dialog { -webkit-transform: translate3d(0, 0, 0); -o-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); }
如果不需要模態框彈出時的動畫效果(淡入淡出效果),刪掉 .fade
類即可
<!-- 觸發模態彈出窗的元素 --> <button type="button" data-toggle="modal" data-target="#mymodal" class="btn btn-primary">點擊</button> <!-- 模態彈出窗 --> <div class="modal" id="mymodal"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title">模態彈出窗標題</h4> </div> <div class="modal-body"> <p>模態彈出窗主體內容</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">關閉</button> <button type="button" class="btn btn-primary">保存</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div><!-- /.modal -->
參數說明
除了通過data-toggle和data-target來控制模態彈出窗之外,Bootstrap框架針對模態彈出框還提供了其他自定義data-屬性,來控制模態彈出窗。有關Modal彈出窗自定義屬性相關說明如下所示
該參數設置在按鈕上,或者彈窗上都可以。出于方便,一般地,在按鈕上設置
[注意]屬性值一定要加引號,如data-backdrop="false"
如果想要支持esc鍵關閉彈窗,需要在彈窗上設置tabindex="-1"
<button type="button" data-toggle="modal" data-target="#mymodal1" class="btn btn-primary">默認樣式</button> <button type="button" data-toggle="modal" data-target="#mymodal2" data-backdrop="false" class="btn btn-primary">無蒙版</button> <button type="button" data-toggle="modal" data-target="#mymodal3" data-keyboard="false" class="btn btn-primary">ESC失效</button> <button type="button" data-toggle="modal" data-target="#mymodal4" data-show="false" class="btn btn-primary">彈窗默認不顯示</button> <div class="modal fade" tabindex="-1" id="mymodal1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title">小火柴的藍色理想</h4> </div> <div class="modal-body"> <p>好的代碼像粥一樣,都是用時間熬出來的</p> </div> </div> </div> </div> <div class="modal fade" tabindex="-1" id="mymodal2"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title">小火柴的藍色理想</h4> </div> <div class="modal-body"> <p>好的代碼像粥一樣,都是用時間熬出來的</p> </div> </div> </div> </div> <div class="modal fade" tabindex="-1" id="mymodal3"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title">小火柴的藍色理想</h4> </div> <div class="modal-body"> <p>好的代碼像粥一樣,都是用時間熬出來的</p> </div> </div> </div> </div> <div class="modal fade" tabindex="-1" id="mymodal4"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title">小火柴的藍色理想</h4> </div> <div class="modal-body"> <p>好的代碼像粥一樣,都是用時間熬出來的</p> </div> </div> </div> </div>
JS觸發
除了使用自定義屬性data-觸發模態彈出框之外,還可以通過JavaScript方法來觸發模態彈出窗。比如說給按鈕設置一個單擊事件,然后觸發模態彈出窗
只需一行 JavaScript 代碼,即可通過元素的 id myModal
調用模態框
$('#myModal').modal()
<button type="button" class="btn btn-primary">點擊</button> <div class="modal fade" tabindex="-1" id="mymodal"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title">小火柴的藍色理想</h4> </div> <div class="modal-body"> <p>好的代碼像粥一樣,都是用時間熬出來的</p> </div> </div> </div> </div> <script> $(function(){ $(".btn").click(function(){ $("#mymodal").modal(); }); }); </script>
使用JavaScript觸發模態彈出窗時,Bootstrap框架提供了一些設置,主要包括屬性設置、參數設置和事件設置
【屬性設置】
模態彈出窗默認支持的自定義屬性主要有
不想讓用戶按ESC鍵關閉模態彈出窗,可以這樣做
$(function(){ $(".btn").click(function(){ $("#mymodal").modal({ keyboard:false }); }); });
【參數設置】
在Bootstrap框架中還為模態彈出窗提供了三種參數設置,具體說明如下
<button type="button" class="btn btn-primary" id="btn" style="position:absolute;z-index:9999">打開(關閉)</button> <div class="modal" tabindex="-1" id="mymodal" > <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title">小火柴的藍色理想</h4> </div> <div class="modal-body"> <p>好的代碼像粥一樣,都是用時間熬出來的</p> </div> </div> </div> </div> <script> ;$(function(){ $("#btn").click(function(){ $("#mymodal").modal("toggle"); }); }); </script>
【事件設置】
模態彈窗還支持五種類型的事件,分別是模態彈出窗的彈出前、彈出后,關閉前、關閉后及遠端數據加載后,具體描述如下:
<button type="button" class="btn btn-primary" id="btn" style="position:absolute;z-index:9999">打開</button> <div class="modal" tabindex="-1" id="mymodal" > <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> <h4 class="modal-title">小火柴的藍色理想</h4> </div> <div class="modal-body"> <p>好的代碼像粥一樣,都是用時間熬出來的</p> </div> </div> </div> </div> <script> ;$(function(){ $("#btn").click(function(){ $("#mymodal").modal("toggle"); }); $('#mymodal').on('hide.bs.modal', function(){ $("#btn").html("打開"); }); $('#mymodal').on('show.bs.modal', function(){ $("#btn").html("關閉"); }); }); </script>
JS解析
【1】IIFE
使用立即調用函數,防止插件內代碼外泄,從而形成一個閉環,并且只能從jQuery的fn里進行擴展
+function ($) { //使用es5嚴格模式 'use strict'; // }(window.jQuery);
【2】初始設置
var Modal = function (element, options) { this.options = options//options是設置選項 this.$body = $(document.body)//body元素 this.$element = $(element)////element表示modal彈出框容器及內容元素 this.$dialog = this.$element.find('.modal-dialog')//彈窗對象 this.$backdrop = null //蒙版對象 this.isShown = null //彈窗是否顯示的標識 this.originalBodyPad = null //body的padding-right標識 this.scrollbarWidth = 0 //滾動條寬度為0 this.ignoreBackdropClick = false //默認蒙板可點擊 //如果設置了remote,就加載remote指定url的內容到modal-content樣式的元素內,并觸發loaded.bs.modal事件 if (this.options.remote) { this.$element .find('.modal-content') .load(this.options.remote, $.proxy(function () { this.$element.trigger('loaded.bs.modal') }, this)) } } //組件版本號3.3.7 Modal.VERSION = '3.3.7' //動畫持續時間300ms Modal.TRANSITION_DURATION = 300 //蒙版動畫持續時間150ms Modal.BACKDROP_TRANSITION_DURATION = 150 //默認設置 Modal.DEFAULTS = { backdrop: true, //顯示蒙版 keyboard: true, //按ESC鍵關閉彈窗 show: true //單擊觸發元素時打開彈窗 }
【3】插件核心代碼
主要是Modal核心類函數的定義、默認參數的定義和9個原型方法的定義,這9個原型方法主要是處理彈窗的反轉、打開、關閉和彈窗背景設置、取消等操作
// 反轉彈窗(打開或關閉) Modal.prototype.toggle = function (_relatedTarget) { //如果彈窗處于顯示狀態,則調用hide()方法,關閉它;否則,調用show()方法,打開彈窗 return this.isShown ? this.hide() : this.show(_relatedTarget) } // 打開彈窗 Modal.prototype.show = function (_relatedTarget) { //保存this值 var that = this //定義彈窗前的觸發事件 var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) //打開彈窗前,觸發事件 this.$element.trigger(e) // 如果已經打開了(或者曾經被阻止過),則退出執行,后續代碼不做處理 if (this.isShown || e.isDefaultPrevented()) return //設置彈窗顯示標識為true this.isShown = true this.checkScrollbar() this.setScrollbar() this.$body.addClass('modal-open') //處理鍵盤事件,主要是設置按esc鍵時是否關閉彈窗 this.escape() this.resize() // 如果單擊了元素內的子元素(帶有[data-dismiss="modal"]屬性),則關閉彈窗 this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) //點擊彈窗時,如果鼠標的目標是當前彈窗,則將默認蒙板不可點擊的標識置為true,并不可再設置 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 () { // 判斷瀏覽器是否支持動畫,并且彈窗是否設置了動畫過渡效果(是否有fade樣式) var transition = $.support.transition && that.$element.hasClass('fade') // 如果modal彈窗沒有父容器,則將它附加到body上 if (!that.$element.parent().length) { that.$element.appendTo(that.$body) } // 顯示modal彈窗 that.$element .show() .scrollTop(0) that.adjustDialog() // 如果支持動畫,強制刷新UI現場,重繪彈窗 if (transition) { that.$element[0].offsetWidth } // 給modal彈窗添加in樣式,和modal樣式一起 that.$element.addClass('in') // 強制給彈窗設定焦點 that.enforceFocus() // 打開彈窗顯示后的觸發事件 var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) transition ? that.$dialog //找到彈窗元素 .one('bsTransitionEnd', function () { // 如果支持動畫,則動畫結束以后給彈窗內的元素設置焦點,并觸發shown事件 that.$element.trigger('focus').trigger(e) }) .emulateTransitionEnd(Modal.TRANSITION_DURATION) : // 否則直接設置焦點,并觸發shown事件 that.$element.trigger('focus').trigger(e) }) } // 關閉彈窗 Modal.prototype.hide = function (e) { //阻止冒泡 if (e) e.preventDefault() //定義關閉彈窗前的觸發事件 e = $.Event('hide.bs.modal') //關閉彈窗前觸發事件 this.$element.trigger(e) // 如果已經關閉了(或者曾經被阻止過),則退出執行,后續代碼不做處理 if (!this.isShown || e.isDefaultPrevented()) return //設置顯示狀態標識為false this.isShown = false //處理鍵盤事件,主要是設置按Esc鍵的時候是否關閉彈窗 this.escape() this.resize() //取消所有的focusin.bs.modal事件 $(document).off('focusin.bs.modal') this.$element .removeClass('in') //刪除in樣式 .off('click.dismiss.bs.modal') //取消dismiss的單擊事件 .off('mouseup.dismiss.bs.modal')//取消dismiss的鼠標抬起事件 //取消dismiss的鼠標放下事件 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() } //強制彈窗處于焦點狀態 Modal.prototype.enforceFocus = function () { $(document) // 禁用所有的focusin事件,防止無限循環 .off('focusin.bs.modal') .on('focusin.bs.modal', $.proxy(function (e) { if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { // 如果處于焦點的元素不是當前元素(或不包含當前元素),則強制給當前元素設置焦點 this.$element.trigger('focus') } }, this)) } //按Esc鍵是否退出的處理 Modal.prototype.escape = function () { if (this.isShown && this.options.keyboard) { //如果彈窗是打開狀態,并且keyboard選項為true,則說明允許按ESC鍵可以關閉彈窗 this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) { //檢測鍵盤事件,如果是ESC(keycode=27),則關閉 e.which == 27 && this.hide() }, this)) } else if (!this.isShown) { // 否則,取消鍵盤事件檢測 this.$element.off('keydown.dismiss.bs.modal') } } Modal.prototype.resize = function () { if (this.isShown) { $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this)) } else { $(window).off('resize.bs.modal') } } //關閉彈窗 Modal.prototype.hideModal = function () { var that = this //關閉彈窗 this.$element.hide() this.backdrop(function () { //移除body上的modal-open樣式 that.$body.removeClass('modal-open') that.resetAdjustments() that.resetScrollbar() //關閉以后,觸發hidden事件 that.$element.trigger('hidden.bs.modal') }) } //刪除蒙版,關閉彈窗時觸發 Modal.prototype.removeBackdrop = function () { // 刪除蒙版 this.$backdrop && this.$backdrop.remove() // 設置蒙版對象為null this.$backdrop = null } //添加蒙版,打開彈窗時觸發 Modal.prototype.backdrop = function (callback) { var that = this //是否設置了動畫過渡效果,如果是則將animate設置為fade var animate = this.$element.hasClass('fade') ? 'fade' : '' //如果是打開狀態,并且設置了backdrop參數 if (this.isShown && this.options.backdrop) { //定義動畫標識 var doAnimate = $.support.transition && animate // 在body上定義蒙版div元素,并附加fade標識以支持動畫 this.$backdrop = $(document.createElement('div')) .addClass('modal-backdrop ' + animate) .appendTo(this.$body) //蒙版被單擊時進行判斷:如果backdrop參數為static,則強制將彈窗設置為售點;否則,關閉彈窗 this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { if (this.ignoreBackdropClick) { this.ignoreBackdropClick = false return } if (e.target !== e.currentTarget) return this.options.backdrop == 'static' ? this.$element[0].focus() : this.hide() }, this)) // 如果支持動畫,強制刷新UI現場,重繪彈窗 if (doAnimate) this.$backdrop[0].offsetWidth //添加in樣式 this.$backdrop.addClass('in') //如果沒有回調,則直接返回 if (!callback) return // 如果支持動畫,則動畫結束執行回調函數;否則,直接執行回調函數 doAnimate ? this.$backdrop .one('bsTransitionEnd', callback) .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : callback() //如果是關閉狀態,但蒙版對象依然還存在 } else if (!this.isShown && this.$backdrop) { //去除in樣式 this.$backdrop.removeClass('in') var callbackRemove = function () { that.removeBackdrop() callback && callback() } // 如果支持動畫,則動畫結束執行回調函數;否則,直接執行回調函數 $.support.transition && this.$element.hasClass('fade') ? this.$backdrop .one('bsTransitionEnd', callbackRemove) .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : callbackRemove() } else if (callback) { callback() } }
【4】滾動條處理
在彈窗插件中,使用了大量的代碼對滾動條進行處理
Modal.prototype.handleUpdate = function () { this.adjustDialog() } //處理因為滾動條而使彈窗位置不固定問題 Modal.prototype.adjustDialog = function () { //如果元素的高度大于頁面的高度,即溢出屏幕,則modalIsOverflowing置為true var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight //將元素的paddingLeft和paddingRight設置為scrollbarWidth this.$element.css({ paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '', paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : '' }) } //重置調節器 Modal.prototype.resetAdjustments = function () { //將元素的paddingLeft和paddingRight置為空 this.$element.css({ paddingLeft: '', paddingRight: '' }) } //檢查滾動條 Modal.prototype.checkScrollbar = function () { //fullWindowWidth儲存頁面寬度 var fullWindowWidth = window.innerWidth //IE8-瀏覽器不支持innerWidth屬性 if (!fullWindowWidth) { //使用getBoundingClientRect方法來獲得頁面寬度 var documentElementRect = document.documentElement.getBoundingClientRect() fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left) } //如果有滾動條,則bodyIsOverflowing置為true this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth //將scrollbarWidth置為實際的滾動條寬度 this.scrollbarWidth = this.measureScrollbar() } //用來為body元素設置padding-right的值,防止body元素被scrollbar阻擋 Modal.prototype.setScrollbar = function () { var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) this.originalBodyPad = document.body.style.paddingRight || '' //如果頁面存在滾動條,則body的padding-right設置為默認的padding-right加上滾動條的寬度 if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) } //重置滾動條 Modal.prototype.resetScrollbar = function () { //將body的padding-right值設置為null this.$body.css('padding-right', this.originalBodyPad) } //測量滾動條寬度 Modal.prototype.measureScrollbar = function () { var scrollDiv = document.createElement('div') scrollDiv.className = 'modal-scrollbar-measure' this.$body.append(scrollDiv) //滾動條寬度等于offetWidth - clientWidth var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth this.$body[0].removeChild(scrollDiv) return scrollbarWidth }
【5】jQuery插件定義
在jQuery上定義插件,有點特殊的代碼是options參數的收集和合并,主要收集了3個部分:插件的默認參數DEFAULTS、modal元素上的data-屬性,執行插件時傳入的option對象,這三個部分的優先級依次升高
function Plugin(option, _relatedTarget) { //根據選擇器,遍歷所有符合規則的元素 return this.each(function () { var $this = $(this) //獲取自定義屬性bs.modal的值 var data = $this.data('bs.modal') //將插件的默認參數DEFAULTS、modal元素上的data-屬性,執行插件時傳入的option對象,這三種值合并到一起,作為options參數 //后面的參數的優先級高于前面的參數 var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) //如果值不存在,則將Modal實例設置為bs.modal值 if (!data) $this.data('bs.modal', (data = new Modal(this, options))) //如果option傳遞了string,則表示要執行某個方法 if (typeof option == 'string') data[option](_relatedTarget) else if (options.show) data.show(_relatedTarget) }) } var old = $.fn.modal //保留其他庫的$.fn.modal代碼(如果定義的話),以便在noConflict之后可以繼續使用該老代碼 $.fn.modal = Plugin //重設插件構造器,可以通過該屬性獲取插件的真實類函數 $.fn.modal.Constructor = Modal
【6】防沖突處理
$.fn.modal.noConflict = function () { //恢復以前的舊代碼 $.fn.modal = old //將$.fn.modal.noConflict()設置為Bootstrap的Modal插件 return this }
【7】綁定觸發事件
//監測所有擁有自定義屬性data-toggle="modal"的元素上的單擊事件 $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { var $this = $(this) //獲取href屬性值 var href = $this.attr('href') //獲取data-target屬性值,如果沒有,則獲取href值,該值是所彈出元素的id var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //如果彈窗元素上已經彈窗實例(即彈出過一次了),則設置option值為字符串toggle,否則將remote值(如果有的話)、彈窗元素上的自定義屬性值集合、觸發元素上的自定義屬性值集合,合并為option對象 var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) //如果是a鏈接,則阻止其默認行為 if ($this.is('a')) e.preventDefault() $target.one('show.bs.modal', function (showEvent) { if (showEvent.isDefaultPrevented()) return //定義一次hidden事件,給所單擊元素設置focus $target.one('hidden.bs.modal', function () { $this.is(':visible') && $this.trigger('focus') }) }) Plugin.call($target, option, this) }) }(jQuery);
文章列表
留言列表