浅析bootstrap插件编写规范

转载.最近学习 bootstrap  转载一下留着用。

bootstrap-button.js插件是一款基于jquery的为html原生的button扩展了一些简单功能的插件,用twitter bootstrap的朋友可能再熟悉不过了,只要向button标签添加一些额外的data属性,我们就能实现点击button出现loading文字以及模拟复选和单选等功能。

下面以bootstrap-button.js的源码为实例,谈一下js插件编写的一些基本规范,笔者也是刚刚接触JS插件,权且拿这一篇,希望能抛砖引玉,欢迎讨论~

1. 源码整体结构

复制代码
1 !function ($) {

3   "use strict"; // jshint ;_;

5  /* BUTTON PUBLIC CLASS DEFINITION
6   * ============================== */
7   var Button = function (element, options) {/*some code*/}
8   Button.prototype.setState = function (state) {/*some code*/}
9   Button.prototype.toggle = function () {/*some code*/}
10 
11  /* BUTTON PLUGIN DEFINITION
12   * ======================== */
13   var old = $.fn.button
14   $.fn.button = function (option) {return this.each(function () {/*some code*/})}
15   $.fn.button.defaults = {loadingText: ‘loading...‘}
16   $.fn.button.Constructor = Button
17 
18  /* BUTTON NO CONFLICT
19   * ================== */
20   $.fn.button.noConflict = function () {$.fn.button = old;return this;}
21 
22  /* BUTTON DATA-API
23   * =============== */
24   $(document).on(‘click.button.data-api‘, ‘[data-toggle^=button]‘, function (e) {/*some code*/})
25 
26 }(window.jQuery);
复制代码

1.1. 定义一个匿名函数,并将jQuery做为函数参数传递进来执行
这样我们就可以在闭包中定义自己的私有函数而不破坏全局的命名空间,而把javascript插件写在一个相对封闭的空间,并开放可以增加扩展的地方,将不可以修改的地方定义成私有成员属性或方法,以遵循“开闭原则”

复制代码
1 !function($){
2     //some code
3 }(window.jQuery)
复制代码
其中,!function(){}()也是匿名函数一种写法,和(function(){})()的写法区别不大,类似的还有+function(){}(), -function(){}(), ~function(){}()等等,只是返回值不同而已

1.2. 匿名函数内的代码构成
PUBLIC CLASS DEFINITION:类定义,定义了插件构造方法类及方法。

PLUGIN DEFINITION:插件定义,上面只是定义了插件的类,这里才是实现插件的地方。

PLUGIN NOCONFLICT:插件命名冲突解决

DATA-API:DATA-属性接口

2. PUBLIC CLASS DEFINITION:插件类定义

2.1. 构造方法:
复制代码
1 var Button = function (element, options) {
2     this.$element = $(element)
3     this.options = $.extend({}, $.fn.button.defaults, options)
4 }
复制代码
这里是JavaScript中OOP思想的体现,定义一个类的构造方法再定义类的方法(属性),这样new出来的对象(类的具体实现)就可以调用类的公共方法和访问类的公共属性了,这里,在Button函数体内部定义的属性和方法可以看做是类的私有属性和方法,为Button.prototype对象定义的属性和方法都可以看做是类的公共属性和方法。这个类封装了插件对象初始化所需的方法和属性。

这样,通过例如var btn = new Button(element, options);我们就定义了一个Button类型的btn对象,这里的this就是btn对象本身

Button(element, options)方法接受两个参数:element和options

element就是与插件相关联的DOM元素,通过

复制代码
this.$element = $(element)
复制代码
将element封装成为一个jQuery对象$element,并由this(btn)对象的$element属性引用

options是插件的一些设置选项,这里简单说一下$.extend(target [, object1] [, objectN]),作用是将object1,...objectN对象合并到target对象中,这是一个在编写jQuery插件过程中经常用到的方法,通过

复制代码
this.options = $.extend({}, $.fn.button.defaults, options)
复制代码
就实现了将用户自定义的options覆盖了插件的默认options: $.fn.button.defaults,并合并到一个空的对象{}中,并由this(btn)对象的options属性引用

通过构造方法,btn的方法setState,toggle就可以调用btn的$element和options属性了

2.2. 类的方法定义:
2.2.1. setState方法:
复制代码
1 Button.prototype.setState = function (state) {
2     var d = ‘disabled‘
3       , $el = this.$element
4       , data = $el.data()
5       , val = $el.is(‘input‘) ? ‘val‘ : ‘html‘

7     state = state + ‘Text‘
8     data.resetText || $el.data(‘resetText‘, $el[val]())

10     $el[val](data[state] || this.options[state])
11 
12     // push to event loop to allow forms to submit
13     setTimeout(function () {
14       state == ‘loadingText‘ ?
15         $el.addClass(d).attr(d, d) :
16         $el.removeClass(d).removeAttr(d)
17     }, 0)
18   }
复制代码
setState(state)方法的作用是为$element添加‘loading...‘(loading...是$.fn.button.defaults属性loadingText默认设置,详见3)

这里简单说几点:

复制代码
val = $el.is(‘input‘) ? ‘val‘ : ‘html‘
复制代码
是为了兼容<button>Submit</button>和<input type="button" value="submit">的两种写法

复制代码
data.resetText || $el.data(‘resetText‘, $el[val]())
复制代码
这是一个小技巧,||是短路或,意即||左边的表达式为true则不执行||右边的表达式,为false则执行||右边的表达式,等价于

复制代码
if(!data.resetText){
    $el.data(‘resetText‘, $el[val]());
}
复制代码
2.2.2. toggle方法:
复制代码
1 Button.prototype.toggle = function () {
2     var $parent = this.$element.closest(‘[data-toggle="buttons-radio"]‘) 
3     $parent && $parent.find(‘.active‘).removeClass(‘active‘)
4     this.$element.toggleClass(‘active‘)
5 }
复制代码
toggle()方法的作用是通过为button添加‘active‘的class来添加“已选中”的CSS样式

这里面

复制代码
$parent && $parent.find(‘.active‘).removeClass(‘active‘)
复制代码
和前面短路或的例子相似,&&是短路与,意即&&左边的表达式为false则不执行&&右边的表达式,为true则执行&&右边的表达式,等价于

复制代码
if($parent){
    $parent.find(‘.active‘).removeClass(‘active‘);
}
复制代码
2.2.3 小结:
定义了插件的类之后,下一步我们要做的是如何快捷的去调用插件,因此我们需要将插件整合到$.fn中,即jQuery对象的原型链中,以便jQuery对象快捷的调用插件

3. PLUGIN DEFINITION:插件定义

3.1 插件的jQuery对象级定义
复制代码
1 $.fn.button = function (option) {
2     return this.each(function () {
3         var $this = $(this)
4         , data = $this.data(‘button‘)
5         , options = typeof option == ‘object‘ && option
6         if (!data) $this.data(‘button‘, (data = new Button(this, options)))
7         if (option == ‘toggle‘) data.toggle()
8         else if (option) data.setState(option)
9     })
10 }
复制代码
首先,$.fn.button=function(){}是在$.fn对象(插件的命名空间)下添加了button属性,这样我们以后就可以通过$(selector).button()来调用插件了,很简单吧!这里扩展一下,为什么在$.fn中添加方法,$(selector)就能直接调用该方法了呢?之前阅读jQuery的源码,发现了这样的架构

复制代码
1 var jQuery = function( selector, context ) {
2     // The jQuery object is actually just the init constructor ‘enhanced‘
3     return new jQuery.fn.init( selector, context, rootjQuery );
4 },
5 //some code
6 jQuery.fn = jQuery.prototype = {/*some code*/}
7 jQuery.fn.init.prototype = jQuery.fn;
复制代码
每次我们写$(selector)实际上就是调用了jQuery(selector)函数一次($是jQuery的别名),都会返回一个jQuery.fn.init类型的对象(每写一次$(selector)都会生成一个不同的jQuery对象),jQuery实际上是一个类(构造方法),jQuery.fn.init也是一个类(构造方法),jQuery.fn正是jQuery.prototype,jQuery.fn.init.prototype也正是jQuery.fn,所以添加到jQuery.fn的方法相当于被添加到了jQuery.fn.init类下面,$(selector)实质上是一个new的jQuery.fn.init类型的对象,理所当然的也就可以调用jQuery.fn.init.prototype下的方法了,也就是jQuery.fn下的方法了。看起来似乎很绕,感觉明明一个new就可以实现的对象为什么绕了这么大个圈子?其实一点都不绕,这里绕了这么多,所以jQuery才能自豪的声称“write less, do more”, 个中奥秘还须慢慢体会。

好像扯的有点远了,还是回归正题,下面这句也是需要注意的地方

复制代码
return this.each(function () {
    var $this = $(this)
    //some code
})
复制代码
通过jQuery.each方法遍历$(selector)的所有DOM元素,然后再通过$(this)将每个遍历到的DOM元素封装为单一的jQuery对象,其作用在于:对于$(selector)得到的结果集,通过形如$(selector).attr(‘class‘)方法得到的是单个结果(第一个匹配的DOM元素的class属性),而不是一组结果,通过$(selector).attr(‘class‘,‘active‘)更会将全部的class设置为active!所以需要将$(selector)的结果集逐一封装成$对象再去get或者set属性,这样才是严谨的做法。

复制代码
if (!data) $this.data(‘button‘, (data = new Button(this, options)))
复制代码

这里是真正用到data = new Button(this, options);的地方,整个$.fn.button做的最主要的事情就是将每个匹配的DOM元素的data-button属性引用new Button(this, options)对象,其次通过判断option来调用toggle方法还是setState方法,至此,插件才算是基本定义完了。

3.2 插件的默认设置定义:
复制代码
1 $.fn.button.defaults = {
2     loadingText: ‘loading...‘
3 }
复制代码
将插件的默认设置做为了$.fn.button的defaults属性,这样做带来的好处就是给用户修改插件的一些默认设置提供了通道,我们只需设置$.fn.button.defaults = {/*some code*/}就改变了插件的默认配置。也就是说,插件对扩展是开放的。

3.3 插件的构造器:
复制代码
1 $.fn.button.Constructor = Button
复制代码
开放了插件的构造方法类做为$.fn.button的Constructor属性,使得用户可以读取插件的构造方法类。

4. NO CONFLICT插件名称冲突解决

复制代码
1 $.fn.button.noConflict = function () {
2     $.fn.button = old
3     return this
4 }
复制代码
用法同$.noConflict,释放$.fn.button的控制权,并重新为$.fn.button声明一个名称,旨在解决插件名称和其他插件有冲突的情况

5. DATA-API DATA-属性接口

复制代码
1 $(document).on(‘click.button.data-api‘, ‘[data-toggle^=button]‘, function (e) {
2     var $btn = $(e.target)
3     if (!$btn.hasClass(‘btn‘)) $btn = $btn.closest(‘.btn‘)
4     $btn.button(‘toggle‘)
5 })
复制代码
此方法,向所有带有data-toggle以button开头的元素绑定了click事件(注意这里用了事件委托的写法)

复制代码
<button data-toggle="button">Click Me</button>
复制代码
好处就是不用再写$(selector).button(options)来初始化插件了,只要页面加载,插件就自动完成初始化了。甚至options的某些属性都可以写在data-属性中,但是$.fn.button.defaults设置的默认属性可能会无效

6.总结

以上就是bootstrap-button.js插件的源码分析,bootstrap-button.js也基本上是bootstrap中最简单的插件了,但是麻雀虽小五脏俱全,bootstrap插件的编写规范也很值得我们来学习,尤其是OOP思想和其他设计模式在插件开发过程中的体现,易维护性和可扩展性等都是我们应该考虑的因素,当然个中细节还需要我们来慢慢体会。
原创地址:http://www.cnblogs.com/fingerdancing/archive/2013/04/30/jsPlugin.html

时间: 2024-07-28 15:37:50

浅析bootstrap插件编写规范的相关文章

jQuery插件编写规范

第一种方法: 在很多基于jQuery或基于Zepto的插件中,在立即函数执行前面会加上";"这个符号. 这是为了防止前面的其他插件没有正常关闭. 在立即执行函数执行时,会一般会传入jQuery,window等.举个例子: ;(function($,window,undefined){ //..... })(jQuery,window) window传递进来作为局部变量存在,而非全局变量,这样可以加快解析流程,以及影响最小化. undefined没有传进来,以便可以确保此undefine

【JavaScript】使用Bootstrap来编写 选择折叠项collapse

选择折叠项collapse在网页中并不常用,不过也并不少见. 这也算是一个比较实用的组件. 折叠项collapse在默认情况下仅能有一项是处于打开状态的. 一.基本目标 使用Bootstrap来编写如下图的选择折叠项: 其中服务条款2在打开网页的时候就是打开状态. 点击不同的折叠项,其余的项就会收起,这项就会打开. 二.制作过程 1.同之前<[JavaScript]使用Bootstrap来编写一个在当前网页弹出的对话框,可以关闭,不用跳转,非弹窗>的第一步(点击打开链接) 因为需要使用Boot

[转载]通达信插件选股(基于通达信插件编程规范的简单分析)

[转载]通达信插件选股(基于通达信插件编程规范的简单分析) 原文地址:通达信插件选股(基于通达信插件编程规范的简单分析)作者:哈尔滨猫猫 首先声明,鄙人是编程人员,不是股民.对选股概念了解甚少.本文仅作编程人员学习借鉴之用.不对选股理论进行探讨和解释. 以前有客户找我做过通达信插件选股的小任务,当时第一次接触面向接口(此类“接口”)编程,也是第一次接触到股票里相关的概念.最近由于接手一个任务,与上次开发相类似,故旧事重提,仔细研究一番.将个人学习研究所得知识与大家分享.在网上搜相关资料,可用的.

【JavaScript】使用Bootstrap来编写 图片轮播Carousel

图片轮播组件是一个在网页中很常见的技术,但是如果直接编写的话,需要很长的JavaScript编码,同时也不好控制大小. 如果使用Bootstrap来编写图片轮播组件Carousel,则能够节约很多时间. 同时说一下,Carousel这个词的本义是回旋木马. 一.基本目标 在网页编写多张图片的轮播组件Carousel,鼠标放在上面自带悬停效果,并且在每张图片下面配有图片说明. 由于笔者的电脑视频录制软件比较渣,也觉得没必要画太多时间在这上面,觉得只要能说明问题就行,所以下面的GIF失色比较严重,但

Bootstrap插件库

简介:Bootstrap 自带 12 种 jQuery 插件,大部分的插件可以在不编写任何代码的情况被触发. 引用方式: 1.可以单独引用相关插件,但是必须明白这些插件之间的依赖关系,使用要求较高 2.引用bootstrap.js 或压缩版的 bootstrap.min.js.                    attention:所有的插件依赖于 jQuery.所以必须在插件文件之前引用 jQuery.请访问 bower.json 查看 Bootstrap 当前支持的 jQuery 版本.

自己动手丰衣足食之征服jQuery插件编写

原文地址:http://www.cnblogs.com/Wayou/p/jquery_plugin_tutorial.html 要说jQuery 最成功的地方,我认为是它的可扩展性吸引了众多开发者为其开发插件,从而建立起了一个生态系统.这好比大公司们争相做平台一样,得平台者得天下.苹果,微软,谷歌等巨头,都有各自的平台及生态圈. 学会使用jQuery并不难,因为它简单易学,并且相信你接触jQuery后肯定也使用或熟悉了不少其插件.如果要将能力上升一个台阶,编写一个属于自己的插件是个不错的选择.

BootStrap插件使用总结

BootStrap插件使用总结 记录下Bootstrap一些常用的插件使用方法,千万要注意插件的版本! 1.Bootstrap Switch 开关控件.相比checkbox,switch就要好看的多了.在bootstrap-switch下载即可,添加css文件,按照amd规范引入.js文件即可,不再过多赘述. require.config({ waitSeconds : 0, paths : { //一些库文件 jquery : '../lib/jquery/jquery-2.1.4.min',

Dz插件编写流程1

插件实现流程 开始编写社区插件,您应当首先对插件实现的流程有一个大致的了解,以下是我们推荐的插件编写流程: 熟练使用 Discuz! 社区系统后,对希望完善或补充的个性化功能进行评估,进而提出插件的功能需求. 对插件做一个概括性的设计,例如:需要使用什么菜单.什么参数,配置哪些选项.数据结构如何设计.前后台实现哪些功能等等. 阅读本文档并在系统设置中实际体验 Discuz! 插件接口所实现的功用,例如:您的插件应当如何设计才能良好的挂接到社区系统中来.插件接口能够实现哪些功能.不能实现哪些功能,

linux驱动模块编写规范以及Makefiel文件的编写规范

内核驱动模块的编写规范 驱动模块一般涉及的必用的头文件: <linux/init.h><linux/module.h><linux/kernel.h> 驱动模块的入口函数的规范: int __init entry_name(void){ /*xxx*/ return 0;} module_init(entry_name); 驱动模块的出口函数规范: void __exit exit_name(void){ } module_exit(exit_name); 模块的信息的