Bootstrap 源码解析

我与大象的故事 2014-04-03

1、Bootstrap的作用域

2、Bootstrap的类定义

3、Bootstrap的插件定义

4、Bootstrap的事件代理

5、Bootstrap的对象数据缓存

6、Bootstrap的防冲突

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

8、Bootstrap的单元测试

Bootstrap的作用域

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

+function ($) { "use strict";
    ...
}(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高级程序设计(第3版)》7.4章节。

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')

相关推荐