欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

深入理解Bootstrap插件机制

来源: 开发者 投稿于  被查看 39108 次 评论:255

深入理解Bootstrap插件机制


最近一直在看Bootstrap,不得不说其中有很多学习的地方。今天我就来讲一讲Bootstrap是如何书写jQuery插件的,希望能给大家一些帮助。
要理Bootstrap的解插件机制,首先要知道他的一些特性。我们打开Bootstrap中文网JavaScript插件这一节,首先就可以看到对bootstrap插件的概览。其中有这么几个特性,单个引入还是全部引入,data属性,编程方式的API,避免命名空间冲突,事件。如果你对这些特性比较了解,一定会对你理解他的插件机制大有裨益的。因为一开始我并没有注意这些特性,而是直接从源码入手,很多都是自己思考的,可以说走了很多弯路。下面我们就看一看一个典型的Bootstrap插件是如何书写的。[code]+function ($) {
'use strict';

// SCROLLSPY CLASS DEFINITION
// ==========================

function ScrollSpy(element, options) {
//构造函数
}

ScrollSpy.prototype.getScrollHeight = function () {}

ScrollSpy.prototype.refresh = function () {}

// SCROLLSPY PLUGIN DEFINITION
// ===========================

function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.scrollspy')
var options = typeof option == 'object' && option

  if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
  if (typeof option == 'string') data[option]()
})

}

var old = $.fn.scrollspy
$.fn.scrollspy = Plugin
$.fn.scrollspy.Constructor = ScrollSpy

// SCROLLSPY NO CONFLICT
// =====================

$.fn.scrollspy.noConflict = function () {
$.fn.scrollspy = old
return this
}

// SCROLLSPY DATA-API
// ==================

$(window).on('load.bs.scrollspy.data-api', function () {
$('[data-spy="scroll"]').each(function () {
var $spy = $(this)
Plugin.call($spy, $spy.data())
})
})

}(jQuery);
[/code]
这里我们对ScrollSpy进行了简化,只保留了一部分函数。从注释就可以看出,ScrollSpy这个插件包括4个部分,第一部分是ScrollSpy类的定义,第二部分是ScrollSpy插件定义,第三部分是去除命名冲突,第四部分是ScrollSpy的DATA-API。
首先Bootstrap允许对某个插件的单独引用,也可以全部引用。这是因为每个Bootstrap插件都是完整的jQuery插件,如上面的代码所示。而Bootstrap.js是所有插件的组合。这样允许我们只加载必要的插件,节省流量。了解了这一特性,你就会知道我们只要对其中一个插件进行讲解,你就可以理解所有的插件机制。下面我们从代码的Plugin部分开始介绍。
Plugin接受一个option参数,这个参数可以是一个对象,也可以是一个字符串。就像官网介绍的使用方式一样,我们可以通过JavaScript代码启动滚动监听插件,如下所示[code]$('body').scrollspy({ target: '#navbar-example' })[/code]我们也可以采用下面的方法来直接调用插件的某一方法[code]var $spy = $(this).scrollspy('refresh')[/code]下面我们就来分析一下Plugin的代码。第一行是return this.each(function(){}),这是什么作用呢?如果去掉each我想你一定明白,就是返回Plugin的调用对象,这样可以实现链式调用。加上each后,其实他还是返回this,因为each本身也是支持链式调用的。那么,这里为甚么要用each呢?这是因为jQuery的选择器引擎。jQuery的选择器引擎是Sizzle,他可以为你的函数提供多个元素,因此我们要为每个元素执行相同的操作。接着,我们把$(this)对象进行了重命名,这不是必须的,但是会让我们的代码更加清晰。此处$(this)就是我们的插件执行主体,是一个jQuery对象。接下来读取了该对象的bs.scrollspy属性,并对传入的option进行了判断,如果是一个对象,就赋值给options属性。接下来的两个if语句,就是插件的关键所在。如果data没有定义,就为该对象的bs.scrollspy属性重新赋值。这里你可以看到,我们是将ScrollSpy的实例直接赋值给了bs.scrollspy属性。这里完成了两个动作,一是实例化ScrollSpy类,二是进行赋值。ScrollSpy类的构造函数中,已经执行了滚动监听的必要函数。因此,我们可以知道ScrollSpy事件已经执行。这就是Bootstrap插件的JavaScript调用机制。传入一个option对象,并对ScrollSpy实例化。注意此处的this[code]data = new ScrollSpy(this, options)[/code],他是一个DOM元素。看到这里,你就可以理解官网上的这句话[code]如果你想获取某个插件的实例,可以直接通过页面元素获取:$('[rel="popover"]').data('popover')。[/code]data属性存储的插件实例,自然可以通过data()函数获取了。如果仅仅是为了实例化一个ScrollSpy类,我们大可以直接new,但是作者为我们提供了一个简便的获取实例的方法,不得不说这个设计十分巧妙。接下来介绍[code]if (typeof option == 'string') data[option]()[/code]这里对输入参数option进行检查,如果是一个字符串,就直接调用ScrollSpy的option方法。就像官网上的介绍的用法[code] 使用滚动监听插件的同时在 DOM 中添加或删除元素后,你需要像下面这样调用此刷新( refresh) 方法
var $spy = $(this).scrollspy('refresh')[/code]插件部分到这里还没有结束,还有最后三行代码[code] var old = $.fn.scrollspy
$.fn.scrollspy = Plugin
$.fn.scrollspy.Constructor = ScrollSpy[/code]前两行明显是为了解决命名冲突的,将原始的$.fn.scrollspy存储在old变量中,并将我们的插件赋值给scrollspy。最后一行代码让我困惑了好久,一开始我以为是继承的写法,但是缺少prototype,而且constructor应该小写才对。后来看了官方文档,每个插件还通过 Constructor 属性暴露了其原始的构造函数:$.fn.ScrollSpy.Constructor。这才豁然大悟,Constructor就是一个普通属性,而不是构造函数,他的作用就是暴露原始构造函数。而且他的用法也十分简单,文档中的用法是这样的[code]每个插件都可以通过修改其自身的Constructor.DEFAULTS 对象从而改变插件的默认设置:
$.fn.modal.Constructor.DEFAULTS.keyboard = false // 将模态框插件的 keyboard 默认选参数置为 false[/code]原来Constructor就是为了让我们访问到Scrollspy的一些属性,豁然大悟,和继承没有一点关系。看到这里你就已经完全理解Bootstrap插件中编程方式的API这一特性了。
第三部分比较简单,为了解决命名冲突,noConflict 方法将原始的old变量赋值给$.fn.srollspy变量。比较值得关注的是他的返回值,this。他返回了调用者本身,也就是ScrollSpy插件。这下我们就可以对他进行重新赋值,更改变量的名称。
最后一部分,是插件的DATA-API。官网中如是说[code]你可以仅仅通过 data 属性 API 就能使用所有的 Bootstrap 插件,无需写一行 JavaScript 代码。这是 Bootstrap 中的一等 API,也应该是你的首选方式。[/code]我们就来看看这传说中的一等API是如何工作的,是不是有他说的这么神呢?
代码中函数为window对象注册了load.bs.scrollspy.data-api事件。这一点比较关键,为什么是window对象,而且是load事件呢?这确保了文档加载完毕后就立即执行,而处理函数中的选择器$('[data-spy="scroll"]')就是我们的DATA-API。仅仅匹配data-spy属性为scroll的元素,并对元素逐一执行Plugin函数。注意Plugin函数的参数, $spy.data()。此处data并没有任何参数,就是读取出$spy对象中的data,并作为option传入Plugin中。最后你可能还会有疑惑,为什么这个load事件的名字起得这么长呢?我们来看看官方的用法你就会明白。[code]话又说回来,在某些情况下可能需要将此功能关闭。因此,我们还提供了关闭 data 属性 API 的方法,即解除以 data-api 为命名空间并绑定在文档上的事件。就像下面这样:
$(document).off('.data-api')[/code]明白了吧?我们可以通过.data-api命名空间解除文档中所有的具有这一命名空间的事件,而不用逐一解除绑定。我想此刻你已经明白了命名空间bs.scroll的作用。
到此,Bootstrap的所有插件部分代码已经讲解完毕。是不是所有的疑问都得到了解决呢?如果还有疑惑,欢迎留言交流。请在最后留下您的脚印,期待你们的回复!

用户评论