웹 프론트엔드 JS 튜토리얼 부트스트랩 모달 창 소스 코드 분석

부트스트랩 모달 창 소스 코드 분석

Feb 11, 2017 pm 04:48 PM
bootstrap

서문:

Bootstrap의 js 플러그인 소스 코드가 매우 잘 작성되어 있으며, 원래 제가 원했던 jquery 플러그인 작성의 모델이라고 볼 수 있습니다. 시간이 없어서 긴 글로 자세히 분석해 봤습니다. 소스 코드를 오래전에 봤는데 지금은 블로그에 올려져 있습니다.

다양한 고급 사용법을 포함한 300줄의 코드입니다. jquery의 소스 코드를 다운로드한 다음 이 기사의 코드를 복사한 다음 실행하고 읽어보세요. 이해가 안 되는 부분이 있으면 메시지를 남겨주시면 답변해 드리겠습니다.

기본적으로 모든 행은 참고용으로 아래에 설명되어 있습니다. 구체적인 내용은 다음과 같습니다

/* ========================================================================
 * 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 중국어 웹사이트를 응원해 주시길 바랍니다.

부트스트랩 모달창 소스코드 분석에 대한 더 많은 글은 PHP 중국어 홈페이지를 주목해주세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 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

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

부트 스트랩 검색 창을 얻는 방법 부트 스트랩 검색 창을 얻는 방법 Apr 07, 2025 pm 03:33 PM

부트 스트랩을 사용하여 검색 표시 줄의 값을 얻는 방법 : 검색 표시 줄의 ID 또는 이름을 결정하십시오. JavaScript를 사용하여 DOM 요소를 얻으십시오. 요소의 값을 가져옵니다. 필요한 작업을 수행하십시오.

Vue에서 부트 스트랩을 사용하는 방법 Vue에서 부트 스트랩을 사용하는 방법 Apr 07, 2025 pm 11:33 PM

vue.js에서 bootstrap 사용은 5 단계로 나뉩니다 : Bootstrap 설치. main.js.의 부트 스트랩 가져 오기 부트 스트랩 구성 요소를 템플릿에서 직접 사용하십시오. 선택 사항 : 사용자 정의 스타일. 선택 사항 : 플러그인을 사용하십시오.

부트 스트랩의 수직 중심을 수행하는 방법 부트 스트랩의 수직 중심을 수행하는 방법 Apr 07, 2025 pm 03:21 PM

부트 스트랩을 사용하여 수직 센터링을 구현하여 : Flexbox Method : D-Flex, 정당화 컨텐츠 중심 및 정렬 중심 센터 클래스를 사용하여 Flexbox 컨테이너에 요소를 배치하십시오. Align-Items-Center 클래스 방법 : Flexbox를 지원하지 않는 브라우저의 경우 상위 요소의 높이가 정의 된 경우 Align-Items 중심 클래스를 사용하십시오.

부트 스트랩에 분할 라인을 작성하는 방법 부트 스트랩에 분할 라인을 작성하는 방법 Apr 07, 2025 pm 03:12 PM

부트 스트랩 분할 라인을 만드는 두 가지 방법이 있습니다 : 태그를 사용하여 수평 분할 라인이 생성됩니다. CSS 테두리 속성을 사용하여 사용자 정의 스타일 분할 라인을 만듭니다.

부트 스트랩 버튼을 사용하는 방법 부트 스트랩 버튼을 사용하는 방법 Apr 07, 2025 pm 03:09 PM

부트 스트랩 버튼을 사용하는 방법? 부트 스트랩 CSS를 소개하여 버튼 요소를 만들고 부트 스트랩 버튼 클래스를 추가하여 버튼 텍스트를 추가하십시오.

부트 스트랩 크기를 조정하는 방법 부트 스트랩 크기를 조정하는 방법 Apr 07, 2025 pm 03:18 PM

부트 스트랩에서 요소의 크기를 조정하려면 다음을 포함하여 차원 클래스를 사용할 수 있습니다.

부트 스트랩을위한 프레임 워크를 설정하는 방법 부트 스트랩을위한 프레임 워크를 설정하는 방법 Apr 07, 2025 pm 03:27 PM

부트 스트랩 프레임 워크를 설정하려면 다음 단계를 따라야합니다. 1. CDN을 통해 부트 스트랩 파일 참조; 2. 자신의 서버에서 파일을 다운로드하여 호스팅하십시오. 3. HTML에 부트 스트랩 파일을 포함; 4. 필요에 따라 Sass/Less를 컴파일하십시오. 5. 사용자 정의 파일을 가져옵니다 (선택 사항). 설정이 완료되면 Bootstrap의 그리드 시스템, 구성 요소 및 스타일을 사용하여 반응 형 웹 사이트 및 응용 프로그램을 만들 수 있습니다.

부트 스트랩에 사진을 삽입하는 방법 부트 스트랩에 사진을 삽입하는 방법 Apr 07, 2025 pm 03:30 PM

Bootstrap에 이미지를 삽입하는 방법에는 여러 가지가 있습니다. HTML IMG 태그를 사용하여 이미지를 직접 삽입하십시오. 부트 스트랩 이미지 구성 요소를 사용하면 반응 형 이미지와 더 많은 스타일을 제공 할 수 있습니다. 이미지 크기를 설정하고 IMG-Fluid 클래스를 사용하여 이미지를 적응할 수 있도록하십시오. IMG 통과 클래스를 사용하여 테두리를 설정하십시오. 둥근 모서리를 설정하고 IMG 라운드 클래스를 사용하십시오. 그림자를 설정하고 그림자 클래스를 사용하십시오. CSS 스타일을 사용하여 이미지를 조정하고 배치하십시오. 배경 이미지를 사용하여 배경 이미지 CSS 속성을 사용하십시오.

See all articles