1. /* ========================================================================
  2. * Bootstrap: modal.js v3.3.5
  3. * http://getbootstrap.com/javascript/#modals
  4. * ========================================================================
  5. * Copyright 2011-2015 Twitter, Inc.
  6. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  7. * ======================================================================== */
  8.  
  9. +function ($) {
  10. 'use strict';
  11.  
  12. // MODAL CLASS DEFINITION
  13. // ======================
  14.  
  15. var Modal = function (element, options) {// element表示modal弹出框容器及内部元
  16. //素,options是设置选项
  17. this.options = options
  18. this.$body = $(document.body)
  19. this.$element = $(element)
  20. this.$dialog = this.$element.find('.modal-dialog')
  21. this.$backdrop = null
  22. this.isShown = null
  23. this.originalBodyPad = null
  24. this.scrollbarWidth = 0
  25. this.ignoreBackdropClick = false
  26.  
  27. // 如果设置了remote,就加载remote指定url的内容到modal-content样式的元素内,并触发
  28. // loaded.bs.modal事件
  29. if (this.options.remote) {
  30. this.$element
  31. .find('.modal-content')
  32. .load(this.options.remote, $.proxy(function () {
  33. this.$element.trigger('loaded.bs.modal')
  34. }, this))
  35. }
  36. }
  37.  
  38. Modal.VERSION = '3.3.5'
  39.  
  40. Modal.TRANSITION_DURATION = 300
  41. Modal.BACKDROP_TRANSITION_DURATION = 150
  42.  
  43. Modal.DEFAULTS = {
  44. backdrop: true,// 默认单击弹窗以外的地方时自动关闭弹窗
  45. keyboard: true,// 默认设置,按Esc键关闭弹窗
  46. show: true// 默认设置,单击触发元素时打开弹窗
  47. }
  48. // 反转弹窗状态
  49. Modal.prototype.toggle = function (_relatedTarget) {
  50. return this.isShown ? this.hide() : this.show(_relatedTarget)
  51. }
  52. // 打开弹窗
  53. Modal.prototype.show = function (_relatedTarget) {
  54. var that = this
  55. var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
  56. // 打开弹窗前,触发事件
  57. this.$element.trigger(e)
  58. // 如果已经打开了(或者曾经被阻止过),则退出执行,后续代码不做处理
  59. if (this.isShown || e.isDefaultPrevented()) return
  60.  
  61. this.isShown = true
  62.  
  63. this.checkScrollbar()
  64. this.setScrollbar()
  65. this.$body.addClass('modal-open')
  66.  
  67. this.escape()
  68. this.resize()
  69. // 如果单击了元素内的子元素(带有[data-dismiss="modal"]属性),则关闭弹窗
  70. this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
  71.  
  72. this.$dialog.on('mousedown.dismiss.bs.modal', function () {
  73. that.$element.one('mouseup.dismiss.bs.modal', function (e) {
  74. if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
  75. })
  76. })
  77.  
  78. this.backdrop(function () {
  79. // 判断浏览器是否支持动画,并且弹窗是否设置了动画过渡效果(是否有fade样式)
  80. var transition = $.support.transition && that.$element.hasClass('fade')
  81. // 如果modal弹窗没有父容器,则将它附加到body上
  82. if (!that.$element.parent().length) {
  83. that.$element.appendTo(that.$body) // don't move modals dom position
  84. }
  85. // 显示modal弹窗
  86. that.$element
  87. .show()
  88. .scrollTop(0)
  89.  
  90. that.adjustDialog()
  91. // 如果支持动画,强制刷新UI现场,重绘弹窗
  92. if (transition) {
  93. that.$element[0].offsetWidth // force reflow
  94. }
  95. // 给modal弹窗添加in样式,和modal样式一起
  96. that.$element.addClass('in')
  97. // 强制给弹窗设定焦点
  98. that.enforceFocus()
  99. // 打开弹窗显示后的触发事件
  100. var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
  101.  
  102. transition ?
  103. that.$dialog // wait for modal to slide in
  104. .one('bsTransitionEnd', function () {// 如果支持动画,则动画结束以后给弹窗内的元素设置焦点,并触发shown事件
  105. that.$element.trigger('focus').trigger(e)
  106. })// 否则直接设置焦点,并触发shown事
  107. .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
  108. that.$element.trigger('focus').trigger(e)
  109. })
  110. }
  111. // 关闭弹窗
  112. Modal.prototype.hide = function (e) {
  113. if (e) e.preventDefault()// 先阻止冒泡行为
  114. // 关闭弹窗前的触发事件
  115. e = $.Event('hide.bs.modal')
  116.  
  117. this.$element.trigger(e)
  118.  
  119. if (!this.isShown || e.isDefaultPrevented()) return
  120.  
  121. this.isShown = false
  122. // 处理键盘事件,主要是设置按Esc键的时候是否
  123. //关闭弹窗
  124. this.escape()
  125. this.resize()
  126.  
  127. $(document).off('focusin.bs.modal')
  128.  
  129. this.$element
  130. .removeClass('in')
  131. .off('click.dismiss.bs.modal')
  132. .off('mouseup.dismiss.bs.modal')
  133.  
  134. this.$dialog.off('mousedown.dismiss.bs.modal')
  135. // 如果支持动画,则动画结束以后再关闭,否则直接关闭
  136. $.support.transition && this.$element.hasClass('fade') ?
  137. this.$element
  138. .one('bsTransitionEnd', $.proxy(this.hideModal, this))
  139. .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
  140. this.hideModal()
  141. }
  142. // 确保当前打开的弹窗处于焦点状态
  143. Modal.prototype.enforceFocus = function () {
  144. $(document)// 禁用所有的focusin事件,防止无限循环
  145. .off('focusin.bs.modal') // guard against infinite focus loop
  146. .on('focusin.bs.modal', $.proxy(function (e) {
  147. if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
  148. this.$element.trigger('focus')
  149. }// 如果处于焦点的元素不是当前元素(或不包含当前元素),则强制给当前元素设置
  150. //焦点
  151. }, this))
  152. }
  153. // 按Esc键是否退出的处理
  154. Modal.prototype.escape = function () {
  155. if (this.isShown && this.options.keyboard) {
  156. this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
  157. e.which == 27 && this.hide()
  158. }, this))
  159. } else if (!this.isShown) {// 否则,取消键盘事件检测
  160. this.$element.off('keydown.dismiss.bs.modal')
  161. }
  162. }
  163.  
  164. Modal.prototype.resize = function () {
  165. if (this.isShown) {
  166. $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
  167. } else {
  168. $(window).off('resize.bs.modal')
  169. }
  170. }
  171. // 关闭弹窗
  172. Modal.prototype.hideModal = function () {
  173. var that = this
  174. this.$element.hide()
  175. this.backdrop(function () {
  176. that.$body.removeClass('modal-open')
  177. that.resetAdjustments()
  178. that.resetScrollbar()
  179. that.$element.trigger('hidden.bs.modal')
  180. })
  181. }
  182. // 删除背景,关闭弹窗时触发
  183. Modal.prototype.removeBackdrop = function () {
  184. this.$backdrop && this.$backdrop.remove()// 删除背景元素
  185. this.$backdrop = null// 设置背景对象为null
  186. }
  187. // 添加背景,打开弹窗时触发
  188. Modal.prototype.backdrop = function (callback) {
  189. var that = this
  190. // 是否设置了动画过渡效果,如果是则
  191. //设置为fade
  192. var animate = this.$element.hasClass('fade') ? 'fade' : ''
  193. // 如果是打开状态,并且设置了backdrop参数
  194. if (this.isShown && this.options.backdrop) {
  195. var doAnimate = $.support.transition && animate
  196.  
  197. // 在body上定义背景div元素,并附加fade标识以支持动画
  198. this.$backdrop = $(document.createElement('div'))
  199. .addClass('modal-backdrop ' + animate)
  200. .appendTo(this.$body)
  201.  
  202. this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
  203. if (this.ignoreBackdropClick) {
  204. this.ignoreBackdropClick = false
  205. return
  206. }
  207. if (e.target !== e.currentTarget) return
  208. this.options.backdrop == 'static'
  209. ? this.$element[0].focus()
  210. : this.hide()
  211. }, this))
  212.  
  213. if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
  214.  
  215. this.$backdrop.addClass('in')
  216.  
  217. if (!callback) return
  218.  
  219. doAnimate ?
  220. this.$backdrop
  221. .one('bsTransitionEnd', callback)
  222. .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
  223. callback()
  224.  
  225. } else if (!this.isShown && this.$backdrop) {
  226. this.$backdrop.removeClass('in')
  227.  
  228. var callbackRemove = function () {
  229. that.removeBackdrop()
  230. callback && callback()
  231. }
  232. $.support.transition && this.$element.hasClass('fade') ?
  233. this.$backdrop
  234. .one('bsTransitionEnd', callbackRemove)
  235. .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
  236. callbackRemove()
  237.  
  238. } else if (callback) {
  239. callback()
  240. }
  241. }
  242.  
  243. // these following methods are used to handle overflowing modals
  244.  
  245. Modal.prototype.handleUpdate = function () {
  246. this.adjustDialog()
  247. }
  248.  
  249. Modal.prototype.adjustDialog = function () {
  250. var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
  251.  
  252. this.$element.css({
  253. paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
  254. paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
  255. })
  256. }
  257.  
  258. Modal.prototype.resetAdjustments = function () {
  259. this.$element.css({
  260. paddingLeft: '',
  261. paddingRight: ''
  262. })
  263. }
  264.  
  265. Modal.prototype.checkScrollbar = function () {
  266. var fullWindowWidth = window.innerWidth
  267. if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
  268. var documentElementRect = document.documentElement.getBoundingClientRect()
  269. fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
  270. }
  271. this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
  272. this.scrollbarWidth = this.measureScrollbar()
  273. }
  274.  
  275. Modal.prototype.setScrollbar = function () {
  276. var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
  277. this.originalBodyPad = document.body.style.paddingRight || ''
  278. if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
  279. }
  280.  
  281. Modal.prototype.resetScrollbar = function () {
  282. this.$body.css('padding-right', this.originalBodyPad)
  283. }
  284.  
  285. Modal.prototype.measureScrollbar = function () { // thx walsh
  286. var scrollDiv = document.createElement('div')
  287. scrollDiv.className = 'modal-scrollbar-measure'
  288. this.$body.append(scrollDiv)
  289. var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
  290. this.$body[0].removeChild(scrollDiv)
  291. return scrollbarWidth
  292. }
  293.  
  294. // MODAL PLUGIN DEFINITION
  295. // =======================
  296.  
  297. function Plugin(option, _relatedTarget) {
  298. return this.each(function () {
  299. var $this = $(this)
  300. var data = $this.data('bs.modal')
  301. var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
  302.  
  303. if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
  304. if (typeof option == 'string') data[option](_relatedTarget)
  305. else if (options.show) data.show(_relatedTarget)
  306. })
  307. }
  308.  
  309. var old = $.fn.modal
  310.  
  311. $.fn.modal = Plugin
  312. $.fn.modal.Constructor = Modal
  313.  
  314. // MODAL NO CONFLICT
  315. // =================
  316.  
  317. $.fn.modal.noConflict = function () {
  318. $.fn.modal = old
  319. return this
  320. }
  321.  
  322. // MODAL DATA-API
  323. // ==============
  324.  
  325. $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
  326. var $this = $(this)
  327. var href = $this.attr('href')
  328. var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
  329. var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
  330.  
  331. if ($this.is('a')) e.preventDefault()
  332.  
  333. $target.one('show.bs.modal', function (showEvent) {
  334. if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
  335. $target.one('hidden.bs.modal', function () {
  336. $this.is(':visible') && $this.trigger('focus')
  337. })
  338. })
  339. Plugin.call($target, option, this)
  340. })
  341.  
  342. }(jQuery);

Bootstrap modal.js 源码分析的更多相关文章

  1. basket.js 源码分析

    basket.js 源码分析 一.前言 basket.js 可以用来加载js脚本并且保存到 LocalStorage 上,使我们可以更加精准地控制缓存,即使是在 http 缓存过期之后也可以使用.因此 ...

  2. events.js 源码分析

    events.js 源码分析 1. 初始化 // 使用 this.ee = new EventEmitter(); // 源码 // 绑定this域,初始化 _events,_eventsCount和 ...

  3. Bootstrap 模态窗口源码分析

    前言: bootstrap的 js插件的源码写的非常好,也算是编写jquery插件的模范写法,本来还想大篇详细的分析一下呢,唉,没时间啊,很早之前看过的源码了,现在贴在了博客上, 300来行的代码,其 ...

  4. Backbone.js源码分析(珍藏版)

    源码分析珍藏,方便下次阅读! // Backbone.js 0.9.2 // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. // Backbone ...

  5. Require.js 源码分析

    本文将简单介绍下个人对require.js的源码分析,简单分析实现原理 一.require加载资源的流程 require中,根据AMD(Asynchronous Module Definition)的 ...

  6. Vue.js 源码分析(三十一) 高级应用 keep-alive 组件 详解

    当使用is特性切换不同的组件时,每次都会重新生成组件Vue实例并生成对应的VNode进行渲染,这样是比较花费性能的,而且切换重新显示时数据又会初始化,例如: <!DOCTYPE html> ...

  7. Vue.js 源码分析(三十) 高级应用 函数式组件 详解

    函数式组件比较特殊,也非常的灵活,它可以根据传入该组件的内容动态的渲染成任意想要的节点,在一些比较复杂的高级组件里用到,比如Vue-router里的<router-view>组件就是一个函 ...

  8. Vue.js 源码分析(二十九) 高级应用 transition-group组件 详解

    对于过度动画如果要同时渲染整个列表时,可以使用transition-group组件. transition-group组件的props和transition组件类似,不同点是transition-gr ...

  9. Vue.js 源码分析(二十八) 高级应用 transition组件 详解

    transition组件可以给任何元素和组件添加进入/离开过渡,但只能给单个组件实行过渡效果(多个元素可以用transition-group组件,下一节再讲),调用该内置组件时,可以传入如下特性: n ...

随机推荐

  1. ThinkPHP5.0框架开发--第9章 TP5.0视图和模板

    ThinkPHP5.0框架开发--第9章 TP5.0视图和模板 第9章 TP5.0视图和模板 ===================================================== ...

  2. Redis-1-安装

    Redis-1-安装 标签(空格分隔): linux,redis 下载 cd /usr/local/src/ wget http://download.redis.io/releases/redis- ...

  3. threejs 入门教程1

    最近在看threejs开发指南,总结一下制作最基础的3d场景的8步: 1. 设置场景大小 2. 创建WebGl渲染器 3. 指定根节点元素 4. 初始化场景 5. 添加相机到场景 6. 创建物体到场景 ...

  4. cell的重用

    cell的重用 简单来说,就是为了节省内存,系统通过一个重用的表示进行获取重用的控件 1 定义重用的标识 NSString * reuseId = @"hero"  //这里的he ...

  5. Spark Streaming 总结

    这篇文章记录我使用 Spark Streaming 进行 ETL 处理的总结,主要包含如何编程,以及遇到的问题. 环境 我在公司使用的环境如下: Spark: 2.2.0 Kakfa: 0.10.1 ...

  6. js小知识 正则表达

    js定义正则表达式有两种方式:普通方式,构造函数方式 正则对象是js的内置对象 正则的属性 正则的方法 js中字符串的方法 一.普通方式(双斜杠//方式):var  reg = /表达式/附加参数 表 ...

  7. python 3.x 学习笔记10 (析构函数and继承)

    1.类变量的用途:大家公用的属性,节省开销(内存) 2.析构函数 在实例释放和销毁的时候执行的,通常用于做一些收尾工作,如关闭一些数据库链接和打开的临时文件 3.私有方法两个下划线开头,声明该方法为私 ...

  8. Apache Ignite - 轉

    Ignite Docs Online: ignite-doc-cn https://dongwq.gitbooks.io/ignite-doc/content/index.html - Apache ...

  9. error C2504: 未定义基类

    出错的情况为: type.h 文件中定义了一个结构体,但只给出了声明 namespace pcl { struct CSDDSignature; } 其定义在type.hpp文件中给出 namespa ...

  10. HDU 1856 More is better【并查集】

    解题思路:将给出的男孩的关系合并后,另用一个数组a记录以find(i)为根节点的元素的个数,最后找出数组a的最大值 More is better Time Limit: 5000/1000 MS (J ...