Bootstrap modal.js 源码分析
/* ========================================================================
* Bootstrap: modal.js v3.3.5
* http://getbootstrap.com/javascript/#modals
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ +function ($) {
'use strict'; // MODAL CLASS DEFINITION
// ====================== var Modal = function (element, options) {// element表示modal弹出框容器及内部元
//素,options是设置选项
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.$dialog = this.$element.find('.modal-dialog')
this.$backdrop = null
this.isShown = null
this.originalBodyPad = null
this.scrollbarWidth = 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))
}
} Modal.VERSION = '3.3.5' Modal.TRANSITION_DURATION = 300
Modal.BACKDROP_TRANSITION_DURATION = 150 Modal.DEFAULTS = {
backdrop: true,// 默认单击弹窗以外的地方时自动关闭弹窗
keyboard: true,// 默认设置,按Esc键关闭弹窗
show: true// 默认设置,单击触发元素时打开弹窗
}
// 反转弹窗状态
Modal.prototype.toggle = function (_relatedTarget) {
return this.isShown ? this.hide() : this.show(_relatedTarget)
}
// 打开弹窗
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') this.escape()
this.resize()
// 如果单击了元素内的子元素(带有[data-dismiss="modal"]属性),则关闭弹窗
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 () {
// 判断浏览器是否支持动画,并且弹窗是否设置了动画过渡效果(是否有fade样式)
var transition = $.support.transition && that.$element.hasClass('fade')
// 如果modal弹窗没有父容器,则将它附加到body上
if (!that.$element.parent().length) {
that.$element.appendTo(that.$body) // don't move modals dom position
}
// 显示modal弹窗
that.$element
.show()
.scrollTop(0) that.adjustDialog()
// 如果支持动画,强制刷新UI现场,重绘弹窗
if (transition) {
that.$element[0].offsetWidth // force reflow
}
// 给modal弹窗添加in样式,和modal样式一起
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 () {// 如果支持动画,则动画结束以后给弹窗内的元素设置焦点,并触发shown事件
that.$element.trigger('focus').trigger(e)
})// 否则直接设置焦点,并触发shown事
.emulateTransitionEnd(Modal.TRANSITION_DURATION) :
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 this.isShown = false
// 处理键盘事件,主要是设置按Esc键的时候是否
//关闭弹窗
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()
}
// 确保当前打开的弹窗处于焦点状态
Modal.prototype.enforceFocus = function () {
$(document)// 禁用所有的focusin事件,防止无限循环
.off('focusin.bs.modal') // guard against infinite focus loop
.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) {
this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
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 () {
that.$body.removeClass('modal-open')
that.resetAdjustments()
that.resetScrollbar()
that.$element.trigger('hidden.bs.modal')
})
}
// 删除背景,关闭弹窗时触发
Modal.prototype.removeBackdrop = function () {
this.$backdrop && this.$backdrop.remove()// 删除背景元素
this.$backdrop = null// 设置背景对象为null
}
// 添加背景,打开弹窗时触发
Modal.prototype.backdrop = function (callback) {
var that = this
// 是否设置了动画过渡效果,如果是则
//设置为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) 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)) if (doAnimate) this.$backdrop[0].offsetWidth // force reflow 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) {
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()
}
} // these following methods are used to handle overflowing modals Modal.prototype.handleUpdate = function () {
this.adjustDialog()
} 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 : ''
})
} Modal.prototype.resetAdjustments = function () {
this.$element.css({
paddingLeft: '',
paddingRight: ''
})
} 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()
} Modal.prototype.setScrollbar = function () {
var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
this.originalBodyPad = document.body.style.paddingRight || ''
if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
} Modal.prototype.resetScrollbar = function () {
this.$body.css('padding-right', this.originalBodyPad)
} Modal.prototype.measureScrollbar = function () { // thx walsh
var scrollDiv = document.createElement('div')
scrollDiv.className = 'modal-scrollbar-measure'
this.$body.append(scrollDiv)
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
this.$body[0].removeChild(scrollDiv)
return scrollbarWidth
} // MODAL PLUGIN DEFINITION
// ======================= function Plugin(option, _relatedTarget) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.modal')
var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
if (typeof option == 'string') data[option](_relatedTarget)
else if (options.show) data.show(_relatedTarget)
})
} var old = $.fn.modal $.fn.modal = Plugin
$.fn.modal.Constructor = Modal // MODAL NO CONFLICT
// ================= $.fn.modal.noConflict = function () {
$.fn.modal = old
return this
} // MODAL DATA-API
// ============== $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
var $this = $(this)
var href = $this.attr('href')
var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) if ($this.is('a')) e.preventDefault() $target.one('show.bs.modal', function (showEvent) {
if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
$target.one('hidden.bs.modal', function () {
$this.is(':visible') && $this.trigger('focus')
})
})
Plugin.call($target, option, this)
}) }(jQuery);
Bootstrap modal.js 源码分析的更多相关文章
- basket.js 源码分析
basket.js 源码分析 一.前言 basket.js 可以用来加载js脚本并且保存到 LocalStorage 上,使我们可以更加精准地控制缓存,即使是在 http 缓存过期之后也可以使用.因此 ...
- events.js 源码分析
events.js 源码分析 1. 初始化 // 使用 this.ee = new EventEmitter(); // 源码 // 绑定this域,初始化 _events,_eventsCount和 ...
- Bootstrap 模态窗口源码分析
前言: bootstrap的 js插件的源码写的非常好,也算是编写jquery插件的模范写法,本来还想大篇详细的分析一下呢,唉,没时间啊,很早之前看过的源码了,现在贴在了博客上, 300来行的代码,其 ...
- Backbone.js源码分析(珍藏版)
源码分析珍藏,方便下次阅读! // Backbone.js 0.9.2 // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. // Backbone ...
- Require.js 源码分析
本文将简单介绍下个人对require.js的源码分析,简单分析实现原理 一.require加载资源的流程 require中,根据AMD(Asynchronous Module Definition)的 ...
- Vue.js 源码分析(三十一) 高级应用 keep-alive 组件 详解
当使用is特性切换不同的组件时,每次都会重新生成组件Vue实例并生成对应的VNode进行渲染,这样是比较花费性能的,而且切换重新显示时数据又会初始化,例如: <!DOCTYPE html> ...
- Vue.js 源码分析(三十) 高级应用 函数式组件 详解
函数式组件比较特殊,也非常的灵活,它可以根据传入该组件的内容动态的渲染成任意想要的节点,在一些比较复杂的高级组件里用到,比如Vue-router里的<router-view>组件就是一个函 ...
- Vue.js 源码分析(二十九) 高级应用 transition-group组件 详解
对于过度动画如果要同时渲染整个列表时,可以使用transition-group组件. transition-group组件的props和transition组件类似,不同点是transition-gr ...
- Vue.js 源码分析(二十八) 高级应用 transition组件 详解
transition组件可以给任何元素和组件添加进入/离开过渡,但只能给单个组件实行过渡效果(多个元素可以用transition-group组件,下一节再讲),调用该内置组件时,可以传入如下特性: n ...
随机推荐
- (OpenGL ES 2.0 Shading Language) attribute 、uniform 和 varying
一:attribute .uniform 和 varying 都是glsl的变量的内存指示器(storage qualifiers),指明变量的内存特性 二:attribute attribute 是 ...
- hdu_2191多重背包
用二维数组解的,因为忘了memset害我wa了好几发... #include<iostream> #include<cstdio> #include<cstring> ...
- HBA卡
HBA,即主机总线适配器英文“Host Bus Adapter”缩写.是一个在服务器和存储装置间提供输入/输出(I/O)处理和物理连接的电路板和/或集成电路适配器. HBA减轻了主处理器在数据存储和检 ...
- HD-ACM算法专攻系列(8)——排序
题目描述: 源码: #include"iostream" #include"string" using namespace std; void Order(in ...
- excel文件使用html导出
<table><tr><td>1</td></tr><tr><td>2</td></tr>& ...
- 洛谷P2118 比例简化(暴力)
题目描述 在社交媒体上,经常会看到针对某一个观点同意与否的民意调查以及结果.例如,对某一观点表示支持的有1498 人,反对的有 902人,那么赞同与反对的比例可以简单的记为1498:902. 不过,如 ...
- P3369 【模板】普通平衡树(Treap/SBT)(pb_ds版)
题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除x数(若有多个相同的数,因只删除一个) 查询x数的排名(若有多个相同的数,因输出最小的排名) 查询 ...
- 脱离node自己使用普通的requirejs管理js资源
首先,工程目录: 现在主页面(web框架写法.html): <!DOCTYPE html> <html lang="en"> <head> &l ...
- php 基础------数组过滤
array_filter();过滤数组 语法: array_filter(array,callbackfunction); array 必写,规定要过滤的数组 callbackfunction 必写, ...
- swift语言点评十八-异常与错误
1.错误类型与枚举的结合 enum VendingMachineError: Error { case invalidSelection case insufficientFunds(coinsNee ...