Bootstrap 源代码分析(未完待续)

网友投稿 196 2023-07-09


Bootstrap 源代码分析(未完待续)

Bootstrap 是最受欢迎的 HTML、css 和 js 框架,用于开发响应式布局、移动设备优先的 WEB 项目。—— Bootstrap 中文文档

Bootstrap 因为支持响应式布局、移动设备优先和易用易学等特点,使得它成为最受欢迎的前端开发框架。

Bootstrap 的响应式设计、组件开发和 javascript 插件开发和 预处理脚本的开发方法,也是值得学习的。

源代码

源代码下载和编译

推荐到 github 下载最新、最全的 Bootstrap 源代码。

GitHub 是 Bootstrap 源代码托管仓库,不仅包含源代码,还包含 Bootstrap 使用文档的源文件。因此,可以在没有网络的情况下,可以通过 编译运行文档源代码,在本地机器上浏览文档。

源代码目录

bootstrap 源代码目录包含:

•文档部署代码子目录 _gh_pages/

 •文档源代码子目录 docs/

 •bootstrap 部署代码子目录 dist/

 •bootstrap 脚本子目录 js/

 •bootstramreTWIp 样式子目录 less/

 •bootstrap 字体子目录 fonts/

 •grunt 构建工具脚本子目录 grunt/

 •包管理器 nuget 子目录 nuget/

 •许多配置文件

切入点

通过 分治 的思想,把复杂的问题分解成许多简单的问题进行解决。当所有小问题都解决了,复杂的问题也就迎刃而解了。

把整个 Bootstrap框架分治成一个个组件,以组件为切入点,理解其工作原理,然后逐步分析整个框架。

组件分析

下拉菜单 dropdown

HTML代码

Dropdown

注意: 代码中去除了源代码中的可访问属性aria-*,便于分析。实际应用中不可省略。有关按钮样式这里也不展开进行分析

CSS代码

// Dropdown arrow/caret

.caret {

display: inline-block;

width: 0;

height: 0;

margin-left: 2px;

vertical-align: middle;

border-top: @caret-width-base dashed;

border-top: @caret-width-base solid ~"\9"; // IE8

border-right: @caret-width-base solid transparent;

border-left: @caret-width-base solid transparent;

}

// The dropdown wrapper (div)

.dropup,

.dropdown {

position: relative; // 父元素相对定位

}

http://

// Prevent the focus on thttp://he dropdown toggle when closing dropdowns

.dropdown-toggle:focus {

outline: 0;

}

// The dropdown menu (ul)

.dropdown-menu {

position: absolute; //子元素绝对定位

top: 100%; // 下拉菜单紧贴父元素下边沿

left: 0;

z-index: @zindex-dropdown;

display: none; //默认隐藏,当触发按钮显示(display:block)

float: left;

min-width: 160px;

padding: 5px 0;

margin: 2px 0 0; // override default ul

list-style: none;

font-size: @font-size-base;

text-align: left;

background-color: @dropdown-bg;

border: 1px solid @dropdown-fallback-border; // IE8 fallback

border: 1px solid @dropdown-border;

border-radius: @border-radius-base;

.box-shadow(0 6px 12px rgba(0,0,0,.175));

background-clip: padding-box;

// Aligns the dropdown menu to right

&.pull-right {

right: 0;

left: auto;

}

// 高度为1px的水平分隔线

.divider {

.nav-divider(@dropdown-divider-bg);

}

// Links within the dropdown menu

> li > a {

display: block;

padding: 3px 20px;

clear: both;

font-weight: normal;

line-height: @line-height-base;

color: @dropdown-link-color;

white-space: nowrap; // 防止链接换行

}

}

// Hover/Focus state

.dropdown-menu > li > a {

&:hover,

&:focus {

text-decoration: none;

color: @dropdown-link-hover-color;

background-color: @dropdown-link-hover-bg;

}

}

// Active state

.dropdown-menu > .active > a {

&,

&:hover,

&:focus {

color: @dropdown-link-active-color;

text-decoration: none;

outline: 0;

background-color: @dropdown-link-active-bg;

}

}

// 显示下拉菜单

.open {

> .dropdown-menu {

display: block; // 显示

}

// Remove the outline when :focus is triggered

> a {

outline: 0;

}

}

// Menu positioning

.dropdown-menu-right {

left: auto; // Reset the default from `.dropdown-menu`

right: 0;

}

// `.pull-right` nav component.

.dropdown-menu-left {

left: 0;

right: auto;

}

// Dropdown section headers

.dropdown-header {

display: block;

padding: 3px 20px;

font-size: @font-size-small;

line-height: @line-height-base;

color: @dropdown-header-color;

white-space: nowrap; // as with > li > a

}

// 非下拉菜单区域

.dropdown-backdrop {

position: fixed;

left: 0;

right: 0;

bottom: 0;

top: 0;

z-index: (@zindex-dropdown - 10); //确保点击下拉菜单时,不会关闭下拉菜单

}

// Right aligned dropdowns

.pull-right > .dropdown-menu {

right: 0;

left: auto;

}

// Allow for dropdowns to go bottom up (aka, dropup-menu)

//

// Just add .dropup after the standard .dropdown class and you're set, bro.

// TODO: abstract this so that the navbar fixed styles are not placed here?

.dropup,

.navbar-fixed-bottom .dropdown {

// Reverse the caret

.caret {

border-top: 0;

border-bottom: @caret-width-base dashed;

border-bottom: @caret-width-base solid ~"\9"; // IE8

content: "";

}

// Different positioning for bottom up menu

.dropdown-menu {

top: auto;

bottom: 100%;

margin-bottom: 2px;

}

}

// Component alignment

//

// Reiterate per navbar.less and the modified component alignment there.

@media (min-width: @grid-float-breakpoint) {

.navbar-right {

.dropdown-menu {

.dropdown-menu-right();

}

// Necessary for overrides of the default right aligned menu.

// Will remove come v4 in all likelihood.

.dropdown-menu-left {

.dropdown-menu-left();

}

}

}

该下拉菜单组件的行为是:当触发按钮被点击,在其下方显示下拉菜单,点击非下拉菜单区域时,隐藏下拉菜单。

实现原理:

 1.开始时只显示触发按钮,.drophttp://down包装默认下拉菜单关闭,.dropdown-menu默认隐藏 display:none

2.当触发按钮被点击,.dropdown后面添加类.open。在.open中 .dropdown-menu的display值是block。所以添加/删除.open类表示下拉菜单的显示/隐藏。

3.点击非下拉菜单区域时,.dropdown删除类.open,即隐藏下拉菜单。非下拉菜单区域的实现的原理是,固定定位,平铺,z-index比下拉菜单小,这样确保点击下拉菜单时,不会隐藏下拉菜单。

javaScript代码

/* ========================================================================

* Bootstrap: dropdown.js v3.3.6

* http://getbootstrap.com/javascript/#dropdowns

* ========================================================================

* Copyright 2011-2016 Twitter, Inc.

* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)

* ======================================================================== */

+function ($) {

'use strict';

// DROPDOWN CLASS DEFINITION

// =========================

var backdrop = '.dropdown-backdrop'

var toggle = '[data-toggle="dropdown"]'

var Dropdown = function (element) {

$(element).on('click.bs.dropdown', this.toggle)

}

Dropdown.VERSION = '3.3.6'

function getParent($this) {

var selector = $this.attr('data-target')

if (!selector) {

selector = $this.attr('href')

selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7

}

var $parent = selector && $(selector)

return $parent && $parent.length ? $parent : $this.parent()

}

function clearMenus(e) {

if (e && e.which === 3) return

$(backdrop).remove()

$(toggle).each(function () {

var $this = $(this)

var $parent = getParent($this)

var relatedTarget = { relatedTarget: this }

if (!$parent.hasClass('open')) return

if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return

$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))

if (e.isDefaultPrevented()) return

$this.attr('aria-expanded', 'false')

$parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))

})

}

Dropdown.prototype.toggle = function (e) {

var $this = $(this)

if ($this.is('.disabled, :disabled')) return

var $parent = getParent($this)

var isActive = $parent.hasClass('open')

clearMenus()

if (!isActive) {

if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {

// if mobile we use a backdrop because click events don't delegate

$(document.createElement('div'))

.addClass('dropdown-backdrop')

.insertAfter($(this))

.on('click', clearMenus)

}

var relatedTarget = { relatedTarget: this }

$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))

if (e.isDefaultPrevented()) return

$this

.trigger('focus')

.attr('aria-expanded', 'true')

$parent

.toggleClass('open')

.trigger($.Event('shown.bs.dropdown', relatedTarget))

}

return false

}

Dropdown.prototype.keydown = function (e) {

if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return

var $this = $(this)

e.preventDefault()

e.stopPropagation()

if ($this.is('.disabled, :disabled')) return

var $parent = getParent($this)

var isActive = $parent.hasClass('open')

if (!isActive && e.which != 27 || isActive && e.which == 27) {

if (e.which == 27) $parent.find(toggle).trigger('focus')

return $this.trigger('click')

}

var desc = ' li:not(.disabled):visible a'

var $items = $parent.find('.dropdown-menu' + desc)

if (!$items.length) return

var index = $items.index(e.target)

if (e.which == 38 && index > 0) index-- // up

if (e.which == 40 && index < $items.length - 1) index++ // down

if (!~index) index = 0

$items.eq(index).trigger('focus')

}

// DROPDOWN PLUGIN DEFINITION

// ==========================

function Plugin(option) {

return this.each(function () {

var $this = $(this)

var data = $this.data('bs.dropdown')

if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))

if (typeof option == 'string') data[option].call($this)

})

}

var old = $.fn.dropdown

$.fn.dropdown = Plugin

$.fn.dropdown.Constructor = Dropdown

// DROPDOWN NO CONFLICT

// ====================

$.fn.dropdown.noConflict = function () {

$.fn.dropdown = old

return this

}

// APPLY TO STANDARD DROPDOWN ELEMENTS

// ===================================

$(document)

.on('click.bs.dropdown.data-api', clearMenus)

.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })

.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)

.on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)

.on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)

}(jquery);

Javascript代码结构可分为三个部分:

 1.类定义 1-125行

 2.插件定义 126-144行

 3.解决冲突 148-153行

 4.应用到标准的下拉菜单元素 155-166行


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java finally块执行时机全面分析
下一篇:java生成图片验证码示例代码
相关文章

 发表评论

暂时没有评论,来抢沙发吧~