ホームページ ウェブフロントエンド jsチュートリアル ブートストラップ モーダル ウィンドウのソース コード分析

ブートストラップ モーダル ウィンドウのソース コード分析

Feb 11, 2017 pm 04:48 PM
bootstrap

前書き:

bootstrap の js プラグインのソース コードは非常によく書かれており、jquery プラグインを作成するためのモデル記述方法とみなすことができます。元々は長い記事で詳細に分析したいと思っていました。ですが、時間がないので、ずっと前に読みました。

コードの多くは、jquery の高度な使用法を含んでいます。ソースをダウンロードすることをお勧めします。 github からコードを取得し、この記事のコードをコピーして、読みながら実行してください。わからないことがあれば、メッセージを残していただければお答えします。

基本的に各行にコメントを付けていますので、具体的な内容は以下の通りです

/* ========================================================================
 * Bootstrap: modal.js v3.3.7
 * http://www.php.cn/
 * ========================================================================
 * Copyright 2011-2016 Twitter, Inc.
 * Licensed under MIT (http://www.php.cn/)
 * ======================================================================== */


+function ($) {
 'use strict';

 // MODAL CLASS DEFINITION
 // ======================

 var Modal = function (element, options) {//modal类:首先是Modal的构造函数,里面声明了需要用到的变量,随后又设置了一些常量。
 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//忽略遮罩成点击吗,不忽略,即:点击遮罩层退出模态

 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.7'

 Modal.TRANSITION_DURATION = 300 //transition duration 过度时间
 Modal.BACKDROP_TRANSITION_DURATION = 150  //背景过度时间

 Modal.DEFAULTS = {//defaults 默认值
 backdrop: true,//有无遮罩层
 keyboard: true,//键盘上的 esc 键被按下时关闭模态框。
 show: true//模态框初始化之后就立即显示出来。
 }
//变量设置完毕,接着就该上函数了。Modal的扩展函数有这么几个:
//toggel,show,hide,enforceFocus,escape,resize,hideModal,removeBackdrop,
//backdrop,handleUpdate,adjustDialog,resetAdjustments,checkScrollbar,setScrollbar,resetScrollbar,
//measureScrollbar终于列完了,恩一共是16个。toggel函数比较简单,是一个显示和隐藏的切换函数。代码如下
 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 })//触发 尾行注册的show.bs.modal事件,并给relatedTarget赋值 $.Event 创建事件对象的目的就是可以给他任意赋值

 this.$element.trigger(e)//

 if (this.isShown || e.isDefaultPrevented()) return//如果已经显示就返回

 this.isShown = true//标记

 this.checkScrollbar()//核对是否有滚动条,并且测量滚动条宽度(非x轴)
 this.setScrollbar()//如果有滚动条,就给body一个padding-right 是一个滚动条的宽度,这一步的目的是为了呼应,下面的去掉y轴滚动条
 this.$body.addClass('modal-open')//接着为body元素添加modal-open类、即去掉y轴滚动条,页面就会往右一个滚动条的宽度,

 this.escape()//按esc退出模态
 this.resize()//窗口大小调整,窗口大小改变,模态框也跟着变

 this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))//注册右上角关闭事件

 this.$dialog.on('mousedown.dismiss.bs.modal', function () {//在dialog中按下鼠标,在父元素中抬起   忽略: 在模态中按下鼠标,在遮罩层中抬起鼠标
  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)//show 并且 弄到顶部

  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)//模态过度完成后,触发foucus 和shown.bs.modal
   })
   .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
  that.$element.trigger('focus').trigger(e)//否则直接进行
 })
 }

 Modal.prototype.hide = function (e) {//他的存在就是一个事件监听函数,所以可以加e 下面是模态窗口关闭处理函数
 if (e) e.preventDefault()//取消默认行为

 e = $.Event('hide.bs.modal')//无论什么事件进入这里都换成 'hide.bs.modal' 妈的这样就通用了,,,无论是点击“x”,还是取消,确定,都这么处理,

 this.$element.trigger(e)//处发hide

 if (!this.isShown || e.isDefaultPrevented()) return

 this.isShown = false//恢复初始的false

 this.escape()//移除esc事件
 this.resize()//移除为window绑定的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))//到了这里,虽然模态已经没有了,但仅仅是把透明度改为0了,this.hideModal才是真正移除
  .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
  this.hideModal()
 }

 Modal.prototype.enforceFocus = function () {//模态框获得焦点
 $(document)
  .off('focusin.bs.modal') // guard against infinite focus loop
  .on('focusin.bs.modal', $.proxy(function (e) {
  if (document !== e.target &&
   this.$element[0] !== e.target &&
   !this.$element.has(e.target).length) {
   this.$element.trigger('focus')
  }
  }, this))
 }

 Modal.prototype.escape = function () {//键盘上的 esc 键被按下时关闭模态框。
 if (this.isShown && this.options.keyboard) {//仅在模态窗显示的时候才注册这个事件
  this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {//不仅可以把事件穿过来,。。。牛
  e.which == 27 && this.hide()//27 时调用hide方法(ps:比if省事多了,高手就是高手)
  }, this))
 } else if (!this.isShown) {//否则移除他,感觉怪怪的,不管了
  this.$element.off('keydown.dismiss.bs.modal')
 }
 }

 Modal.prototype.resize = function () {//为你window resize注册事件
 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
 }

 Modal.prototype.backdrop = function (callback) {
 var that = this
 var animate = this.$element.hasClass('fade') ? 'fade' : ''//是否有fade动画类

 if (this.isShown && this.options.backdrop) {//条件:正在show,并且有遮罩层
  var doAnimate = $.support.transition && animate// do的条件是支持css3过度和有fade class

  this.$backdrop = $(document.createElement('p'))//创建遮罩层p
  .addClass('modal-backdrop ' + animate)//添加 modal-backdrop 和fade class
  .appendTo(this.$body)//加到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')//添加in 0.5的透明度

  if (!callback) return

  doAnimate ?
  this.$backdrop
   .one('bsTransitionEnd', callback)
   .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) ://如果有fade动画的话 就给遮罩层绑定一个遮罩过度时间,为什么要这么写以后聊
  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 () {//用来为body元素设置padding-right的值,防止body的元素被scrollbar阻挡
 var bodyPad = parseInt((this.$body.css(&#39;padding-right&#39;) || 0), 10)
 this.originalBodyPad = document.body.style.paddingRight || &#39;&#39;
 if (this.bodyIsOverflowing) this.$body.css(&#39;padding-right&#39;, bodyPad + this.scrollbarWidth)
 }

 Modal.prototype.resetScrollbar = function () {
 this.$body.css(&#39;padding-right&#39;, this.originalBodyPad)
 }

 Modal.prototype.measureScrollbar = function () { // thx walsh 测量 Scrollbar
 var scrollp = document.createElement(&#39;p&#39;)
 scrollp.className = &#39;modal-scrollbar-measure&#39;
 this.$body.append(scrollp)
 var scrollbarWidth = scrollp.offsetWidth - scrollp.clientWidth
 this.$body[0].removeChild(scrollp)
 return scrollbarWidth
 }


 // MODAL PLUGIN DEFINITION
 // =======================

 function Plugin(option, _relatedTarget) {
 return this.each(function () {
  var $this = $(this)
  var data = $this.data(&#39;bs.modal&#39;)//如果是第二次打开模态窗口,这个数据才会有
  var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == &#39;object&#39; && option)//合并一下默认参数
  //
  if (!data) $this.data(&#39;bs.modal&#39;, (data = new Modal(this, options)))//把modal对象存起来,避免第二次打开时在new对象,这点值得学习
  if (typeof option == &#39;string&#39;) data[option](_relatedTarget)/*这里是区分option是对象和字符串的情况*/
  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 这里是不用一行js代码就实现modal的关键
 // ==============

 $(document).on(&#39;click.bs.modal.data-api&#39;, &#39;[data-toggle="modal"]&#39;, function (e) {//点击按钮的时候触发模态框的东西,
 var $this = $(this)
 var href = $this.attr(&#39;href&#39;)
 var $target = $($this.attr(&#39;data-target&#39;) || (href && href.replace(/.*(?=#[^\s]+$)/, &#39;&#39;))) // strip for ie7
 var option = $target.data(&#39;bs.modal&#39;) ? &#39;toggle&#39; : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())//这地方是区别一下第一次触发和第二次触发
  //到这里为止是为了得到被控制的modal的dom元素
 if ($this.is(&#39;a&#39;)) e.preventDefault()

 $target.one(&#39;show.bs.modal&#39;, function (showEvent) {//调用show方法后立即执行的事件
  if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
  $target.one(&#39;hidden.bs.modal&#39;, function () {//调用show后创建的事件,模态框隐藏后触发,
  $this.is(&#39;:visible&#39;) && $this.trigger(&#39;focus&#39;)//如果原来的按钮还存在的(或显示的)话,那就让他得到焦点
  })
 })
 Plugin.call($target, option, this)
 })

}(jQuery);
ログイン後にコピー

以上が皆さんの学習に役立つことを願っています。 PHP中国語ネットをサポートします。

Bootstrap モーダル ウィンドウのソース コード分析に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

ブートストラップ検索バーを取得する方法 ブートストラップ検索バーを取得する方法 Apr 07, 2025 pm 03:33 PM

ブートストラップを使用して検索バーの値を取得する方法:検索バーのIDまたは名前を決定します。 JavaScriptを使用してDOM要素を取得します。要素の値を取得します。必要なアクションを実行します。

VueでBootstrapの使用方法 VueでBootstrapの使用方法 Apr 07, 2025 pm 11:33 PM

vue.jsでBootstrapを使用すると、5つのステップに分かれています。ブートストラップをインストールします。 main.jsにブートストラップをインポートしますブートストラップコンポーネントをテンプレートで直接使用します。オプション:カスタムスタイル。オプション:プラグインを使用します。

ブートストラップの垂直センタリングを行う方法 ブートストラップの垂直センタリングを行う方法 Apr 07, 2025 pm 03:21 PM

ブートストラップを使用して垂直センタリングを実装します。FlexBoxメソッド:D-Flex、Justify-Content-Center、Align-Items-Centerクラスを使用して、FlexBoxコンテナに要素を配置します。 ALIGN-ITEMS-CENTERクラス方法:FlexBoxをサポートしていないブラウザの場合、親要素の高さが定義されている場合、Align-Items-Centerクラスを使用します。

ブートストラップにスプリットラインを書く方法 ブートストラップにスプリットラインを書く方法 Apr 07, 2025 pm 03:12 PM

ブートストラップスプリットラインを作成するには2つの方法があります。タグを使用して、水平方向のスプリットラインを作成します。 CSS Borderプロパティを使用して、カスタムスタイルのスプリットラインを作成します。

ブートストラップボタンの使用方法 ブートストラップボタンの使用方法 Apr 07, 2025 pm 03:09 PM

ブートストラップボタンの使用方法は?ブートストラップCSSを導入してボタン要素を作成し、ブートストラップボタンクラスを追加してボタンテキストを追加します

ブートストラップのサイズを変更する方法 ブートストラップのサイズを変更する方法 Apr 07, 2025 pm 03:18 PM

Bootstrapの要素のサイズを調整するには、次のものを含むDimensionクラスを使用できます。

ブートストラップのフレームワークをセットアップする方法 ブートストラップのフレームワークをセットアップする方法 Apr 07, 2025 pm 03:27 PM

Bootstrapフレームワークをセットアップするには、次の手順に従う必要があります。1。CDNを介してブートストラップファイルを参照してください。 2。独自のサーバーでファイルをダウンロードしてホストします。 3。HTMLにブートストラップファイルを含めます。 4.必要に応じてSASS/LESSをコンパイルします。 5。カスタムファイルをインポートします(オプション)。セットアップが完了したら、Bootstrapのグリッドシステム、コンポーネント、スタイルを使用して、レスポンシブWebサイトとアプリケーションを作成できます。

ブートストラップに写真を挿入する方法 ブートストラップに写真を挿入する方法 Apr 07, 2025 pm 03:30 PM

ブートストラップに画像を挿入する方法はいくつかあります。HTMLIMGタグを使用して、画像を直接挿入します。ブートストラップ画像コンポーネントを使用すると、レスポンシブ画像とより多くのスタイルを提供できます。画像サイズを設定し、IMG-Fluidクラスを使用して画像を適応可能にします。 IMGボーダークラスを使用して、境界線を設定します。丸い角を設定し、IMGラウンドクラスを使用します。影を設定し、影のクラスを使用します。 CSSスタイルを使用して、画像をサイズ変更して配置します。背景画像を使用して、背景イメージCSSプロパティを使用します。

See all articles