1、Bootstrap的作用域

2、Bootstrap的类定义

3、Bootstrap的插件定义

4、Bootstrap的事件代理

5、Bootstrap的对象数据缓存

6、Bootstrap的防冲突

7、作用域外如何使用Button类

8、Bootstrap的单元测试

Bootstrap的作用域

Bootstrap每个插件都定义在下面这段作用域代码中:

+function ($) {
...
}(window.jQuery)

请看《IIFE》和《严格模式》编译环境。

在插件的作用域之外,全局范围执行代码的第一行,检测了jQuery是否定义。在Grunt的concat任务中,合并所有插件时,检测代码添加在目标文件的banner说明后面。Grunt.js的相关代码:

jqueryCheck: 'if (typeof jQuery === "undefined") { throw new Error("Bootstrap requires jQuery") }\n\n',

concat: {
options: {
banner: '<%= banner %><%= jqueryCheck %>',
stripBanners: false
},
bootstrap: {
src: [
'js/transition.js',
'js/alert.js',
'js/button.js',
'js/carousel.js',
'js/collapse.js',
'js/dropdown.js',
'js/modal.js',
'js/tooltip.js',
'js/popover.js',
'js/scrollspy.js',
'js/tab.js',
'js/affix.js'
],
dest: 'dist/js/<%= pkg.name %>.js'
}
}

Bootstrap的类定义

  var Button = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, Button.DEFAULTS, options)
} Button.DEFAULTS = {
loadingText: 'loading...'
} Button.prototype.setState = function (state) {
...
} Button.prototype.toggle = function () {
...
}

Bootstrap采用这种类定义方式的好处,以及Javascript其他几种类定义的方式,请参照《Javascript面向对象编程(一):封装

Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。在Button函数体内部定义的属性和方法可以看做是类的私有属性和方法, 为Button.prototype对象定义的属性和方法都可以看做是类的公共属性和方法。这个类封装了插件对象初始化所需的方法和属性。

Bootstrap的插件定义

请参看《jQuery插件开发快速入门》,注意两个this指向的是不同对象

  $.fn.button = function (option) {
return this.each(function () {
var $this = $(this)
...
})
}

Bootstrap的事件代理

Bootstrap Button插件定义最后一部分,事件绑定是这么写的

$(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) {
...
})

这段JavaScript代码将click委托事件监听器绑定在document元素上,并给click事件赋予命名空间click.bs.button.data-api,选择器匹配的是属性data-toggle的值为"button"开头的标签。

关于jQuery将事件绑定在document文档对象上的好处,就是js事件代理的优点,性能上做了一个测试比较

关于jQuery命名空间的好处,请参看《jQuery .on() and .off() 命名空间

Bootstrap的防止冲突

jQuery是全局对象,所以jQuery的插件定义$.fn.button并不受作用域限制。如果在别的插件中同样定义了button插件,后加载的button插件将会覆盖先加载的button插件,jsbin示例

// Old button
+function($){
$.fn.button = function() {
alert('Old button')
}
}(window.jQuery) // Bootstrap button
+function($){
$.fn.button = function() {
alert('Bootstrap button')
}
}(window.jQuery) $('a').button() // alert('Bootstrap button')

Bootstrap做了插件冲突处理,jsbin示例

// Old button
+function($) {
$.fn.button = function() {
alert('Old button')
}
}(window.jQuery) // Bootstrap button
+function($){
// 将原先的button插件对象赋值给一个临时变量old
var old = $.fn.button $.fn.button = function() {
alert('Bootstrap button')
} // 执行该函数,恢复原先的button定义,并返回Bootstrap定义的button插件
$.fn.button.noConflict = function () {
$.fn.button = old
return this
} }(window.jQuery) // <span style="font-family: Helvetica, Tahoma, Arial, sans-serif; white-space: normal; background-color: #ffffff;">作用域</span>外我们可以灵活使用两个button插件
$.fn.button = $.fn.button.noConflict()
$('a').button() // alert('Bootstrap button') $.fn.button.noConflict()
$('a').button() // alert('Old button')

Bootstrap作用域外如何使用Button类

$.fn.button.Constructor = Button

在Bootstrap的button插件中还有上面者句代码,去掉它不影响插件的正确执行。

它很像javascript中类构造器:

var Cat = function(name) {
this.name = name
}
var cat1 = new Cat('Hello Kitty')
var cat2 = new Cat('Doramon') cat1.constructor == Cat.prototype.constructor

但是Javascript是区分大小写的,也就是 这里大写开头的的Constructor 和 Javascript小写开头的constructor 没有任何关系。

查找jQuery源码中也没有对于大写开头的Constructor的定义。所以这里的Constructor只是一个普通属性,我们也可以写成其他名字 $.fn.button.Something = Button,Bootstrap为了指明这个属性的意义而命名为构造器“Constructor”更合理。

这样一来,这段代码就很好理解了:$.fn.button.Constructor = Button 通过将作用域内的Button类赋值给jQuery的button对象的Constructor属性,在IIFE作用域外也可以使用Button类。调用方式:

+function($){
// 类定义
var Button = function() {}
// 插件定义
$.fn.button = function() {
alert('Bootstrap button')
}
// 类赋值到jQuery button对象的Constructor属性
$.fn.button.Constructor = Button }(window.jQuery) var Button = $.fn.button.Constructor

Bootstrap的对象数据缓存

// 获取存储的Button对象,如果是第一次执行变量data的值为undefined
var data = $this.data('bs.button')
var options = typeof option == 'object' && option // 创建Button对象: new Button(this, options),
// 并赋值给变量data: data = new Button(this, options)
// 存储在元素的jQuery对象上的‘bs.button’数据字段 $this.data('bs.button', data)
if (!data) $this.data('bs.button', (data = new Button(this, options))) // data是一个Button对象,可以调用Button的原生方法
if (option == 'toggle') data.toggle()
else if (option) data.setState(option)

利用jQuery的 .data(key, value)存储Button对象

Bootstrap的单元测试

QUnit + PhantomJS

优秀的程序猿有一个共同的秘诀:阅读优秀的代码。

http://suqing.iteye.com/blog/1984131

最新文章

  1. Dedecms有效防止采集的两个实用办法
  2. 排序系列 之 折半插入排序算法 —— Java实现
  3. Linux—C内存管理
  4. Linux 下 Oracle 内核参数优化
  5. android首次点击没反应,第二次才反应
  6. PyCharm 4.5.4 环境配置
  7. sql语句or与union all的执行效率比较
  8. POJ1523 SPF(割点模板)
  9. jquery中的事件进阶
  10. 离线安装chrome插件
  11. magento添加系统sections配置时应注意的事项
  12. 用css3动画 @keyframes里设置transform:rotate(); 控制动画暂停和运动用属性:animation-play-state:paused暂停,在微信和safari里设置paused无效,在QQ里是正常的
  13. Notepad++使用教程
  14. JS银行取款流程
  15. Linux:nohub启动后台永久进程
  16. 百度的android面试总结分析
  17. shell编程练习-打印九九乘法表(附:awk编程)
  18. 博弈论入门之nim游戏
  19. Centos7 关于防火墙的一些简单配置
  20. 记一次wepy里面的渲染问题(this.$apply()的使用)

热门文章

  1. SIM900A访问HTTP的简单方法
  2. JavaScript技巧45招
  3. StatusStrip状态栏控件
  4. Android中9patch图片格式(xx.9.png)介绍与制作详解
  5. 隐藏和显示效果js动画
  6. 动态设置uitableview高度,参考
  7. 怎样快糙猛的开始搞Kaggle比赛
  8. hdu 1018
  9. 定长内存池之BOOST::pool
  10. UIActinSheet和UIActionSheetDelegate