微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

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

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

源代码

源代码下载和编译

推荐到 GitHub 下载最新、最全的

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

源代码目录

包含: •文档部署代码子目录 _gh_pages/ •文档源代码子目录 docs/ •bootstrap 部署代码子目录 dist/ •bootstrap 脚本子目录 js/ •bootstrap 样式子目录 less/ •bootstrap 字体子目录 fonts/ •grunt 构建工具脚本子目录 grunt/ •包管理器 nuget 子目录 nuget/ •许多配置文件

切入点

Bootstrap 框架的源代码很复杂,要从作者开发框架的角度分析,无疑是很困难的。可以对问题进行简单化,不关注框架是怎么构建或部署的,只关注框架的工作原理,即 HTML、CSS/LESS 和 JS 部分。

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

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

组件分析

下拉菜单 dropdown

HTML代码

rush:xhtml;">

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

CSS代码

<div class="jb51code">
<pre class="brush: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; // 父元素相对定位
}

// Prevent the focus on the 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,.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.开始时只显示触发按钮,.dropdown包装认下拉菜单关闭,.dropdown-menu认隐藏 display:none

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

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

JavaScript代码

<div class="jb51code">
<pre class="brush:js;">
/* ========================================================================

+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',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行

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐