bootstrap是twitter公司基于HTML5、CSS3和jQuery创建的一种前端框架,是现在使用范围比较广泛的一种前端框架,其源码对于学习前端的一些技术非常有帮助。
bootstrap源码可以从bootstrap中文网(http://www.bootcss.com/)上面下载,但是安装源码需要配置Nodejs环境,安装方法可以自行百度。这个网站上面也可以下载到用于生产的精简源码。
bootstrap源码主要有几个部分,包括样式表,脚本以及字体库等等,其中最重要的就是脚本,所以这里只拿脚本来进行分析。
+function ($) {
//+function中的+号仅仅表示添加的意思,并没有实际效果
'use strict';
//use strict放在函数的开头表示函数咋在严格模式下运行
var version = $.fn.jquery.split(' ')[0].split('.')
...... //版本检测
}
}(jQuery);
bootstrap源代码中bootstrap.js文件中的所有插件都是这样的结构,首先插件是以一个直接运行的匿名函数构造的,这个匿名函数的形参是$,实参是jQuery对象,并且在function关键前面有一个+号,这个加号并没有实际的含义,这个符号仅仅表示添加一个函数。所有的bootstrap插件都是在严格模式下运行的,以标记”use strict”来表示出来,并且bootstrap插件使用的是jQuery进行编写的,所以首先要检测jQuery的版本是否足够,我现在使用的是3.3.5版本的bootstrap,这个版本要求的jQuery的最低版本是1.9.1。
bootstrap中的基本所有的动画都是使用CSS过渡来完成的,并没有使用jQuery自带的动画函数来完成。所以需要检测浏览器内核版本来确定CSS中使用transition的前缀。transitionEnd事件是在CSS过渡完成之后自动触发的一个事件,有些动画需要在动画结束之后对执行动画的元素进行一些收尾工作,包括数据清理等,所以需要一个可以触发的事件,用来给他绑定回调函数。
具体和CSS过渡有关的内容可以点这里:CSS过渡&&bootstrap transition
+function ($) {
//检测浏览器支持的CSS transition属性名。和浏览器有关
function transitionEnd() {
var el = document.createElement('bootstrap')
var transEndEventNames = {
WebkitTransition : 'webkitTransitionEnd',
MozTransition : 'transitionend',
OTransition : 'oTransitionEnd otransitionend',
transition : 'transitionend'
}
for (var name in transEndEventNames) {
if (el.style[name] !== undefined) {
return { end: transEndEventNames[name] }
}
}
return false
}
// 扩展jQuery.fn对象,添加实例化方法emulateTransitionEnd,这个方法是保证如果
// transitionEnd事件没有被正确触发,那么会自动在duration时间段后进行回调
$.fn.emulateTransitionEnd = function (duration) {
.......
setTimeout(callback, duration)
return this
}
$(function () {
//增加一个support变量transition,其值为当前浏览器适应的transition版本
$.support.transition = transitionEnd()
})
}(jQuery);
bootstrap插件的基本所有插件的代码风格都十分相似,基本的函数,冲突检测,插件注册方法基本都是一样,这里用一段比较短的Alert类进行分析吧(因为实在是太懒了,第二短的button都要几百行代码lol)。
+function ($) {
//省略了源码中部分的变量声明和初始化。如果想看完整代码要去bootstrap中文网自己安装哦
var dismiss = '[data-dismiss="alert"]'
var Alert = function (el) {
$(el).on('click', dismiss, this.close)
} //也就是给el元素中的第一个具有符合dismiss的元素添加onclick的事件处理函数
Alert.prototype.close = function (e) {
var $this = $(this)
var selector = $this.attr('data-target')
//寻找data-target指定的关闭对象,如果没有指定关闭对象,则从href中获取,如果href中仍
//没有关闭对象,那就从叉号的祖先元素中获取类为alert的对象进行关闭
if (!selector) {
selector = $this.attr('href')
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
var $parent = $(selector)
if (e) e.preventDefault()
//解除点击事件的默认事件处理函数
if (!$parent.length) {
$parent = $this.closest('.alert')
//寻找x按钮的祖先元素中的class=alert的元素,也就是需要关闭的元素
}
$parent.trigger(e = $.Event('close.bs.alert'))
//新建一个事件close.bs.alert,并且用这个事件来触发上面选中的parent元素
if (e.isDefaultPrevented()) return
$parent.removeClass('in')
function removeElement() {
// detach from parent, fire event then clean up data
$parent.detach().trigger('closed.bs.alert').remove()
//移除选中的祖先节点并且取消其事件,清理数据内容
}
$.support.transition && $parent.hasClass('fade') ?
$parent
.one('bsTransitionEnd', removeElement) //在transition动画完毕之后,调用一次removeElement函数
.emulateTransitionEnd(Alert.TRANSITION_DURATION) : //emulateTransitionEnd是防止TransitionEnd不发生而设置的定时函数
removeElement()
//检测支持的transition动画版本,如果存在则使用动画渐隐元素
}
}(jQuery);
上面这段代码片是bootstrap用来关闭alert的x号的,首先为x号注册鼠标单击的事件处理函数。之后完成这整个事件处理函数,事件处理函数中首先需要选择要关闭的对象,采用了三层选择方法,第一层首先选择x号本身指定的对象,对象名为x号里面的data-target属性,第二层使用x号内部href对应的对象名,第三层通过x按钮来寻找其祖先元素中的具有class=“alert”属性的元素来进行关闭。
bootstrap采用一个新建的事件名来触发关闭事件:
$parent.trigger(e = $.Event('close.bs.alert'))
之后通过之前的CSS过渡动画来移除元素的表现,在动画完成之后触发transitionEnd事件,用其回调函数来清理数据。如果没有自动触发transitionEnd事件,则调用emulateTransitionEnd方法来清理数据。
插件初始化方法:
function Plugin(option) {
//this指向jQuery对象,this.each遍历所有DOM元素,每个元素都调用function函数
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.alert')
//取得与bs.alert相关的数据项,如果没有数据项则新赋值一个数据项
//data变量是用来检测插件是否初始化过的一句
if (!data) $this.data('bs.alert', (data = new Alert(this)))
if (typeof option == 'string') data[option].call($this)
})
}
插件的冲突检测方法:
var old = $.fn.alert
$.fn.alert = Plugin
$.fn.alert.Constructor = Alert
//冲突检测,假设有原本的其他插件的alert方法,那么将原本的alert方法
//赋值给一个临时变量old,然后在调用$.fn.alert.noConfict方法的时候,
//这个方法将原本的alert方法old还原到alert方法上,并且返回bootstrap版本
//的alert方法
$.fn.alert.noConflict = function () {
$.fn.alert = old
return this
}
这个冲突检测方法十分的精巧,既可以防止冲突,又可以安全的调用新的和旧的方法。
可以通过下面这个例子更好的了解bootstrap的冲突检测方法:
+function($){
$.fn.alert = function(){
alert("这是旧的alert方法");
};
}(jQuery);
+function($) {
var old = $.fn.alert;
$.fn.alert = function(){
alert("这是新的alert方法");
};
$.fn.alert.noConflict = function () {
$.fn.alert = old;
return this;
}
}(jQuery);
$.fn.alert(); //这是新的alert方法
var newAlert = $.fn.alert.noConflict();
$.fn.alert(); //这是旧的alert方法
newAlert(); //这是新的alert方法
插件的智能注册方法:
$(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
//这段JavaScript代码将click委托事件监听器绑定在document元素上,
//并给click事件赋予命名空间click.bs.alert.data-api,
//选择器匹配的是属性data-dismiss的值为"alert"的标签。
基本上所有的bootstrap源码都是用这种结构写的插件,非常值得读一下,阅读好的代码是一个好的程序猿的必修课。。