jQuery插件开发的五种形态小结

关于jQuery插件的开发自己也做了少许研究,自己也写过多个插件,在自己的团队了也分享过一次关于插件的课。开始的时候整觉的很复杂的代码,现在再次看的时候就清晰了许多。这里我把我自己总结出来的东西分享出来,帮助那些和我一样曾经遇到过同样问题的人。

要做什么 我想要得到的javascript 插件应该会有以下几个特征

代码相对独立 链式操作 插件可配置 有可操作的方法插件的生命周期可控制 配置可被缓存 可扩展 无冲突处理 事件代理,动态初始化

* 以下的代码均假设存在 jQuery

插件的第一形态

面对这种情况,通常我们会通过定义function的方式来实现。

代码如下:

因为我谈的是jQuery插件开发,那么我现在把这段代码扩展到jQuery上,代码如下:

代码如下:

但是还差的远,目前只解决了两个问题

代码相对独立 链式操作 插件可配置 有可操作的方法,插件的生命周期可控制 配置可被缓存 可扩展 无冲突处理 事件代理,动态初始化

插件的第二形态

现在来给插件添加参数支持。代码如下

代码如下:
默认参数和自定义参数 var args = $.extend({},$.fn.pluginName.defaults,options); return this.each(function() { console.log(args.text); // to do something... }); }; // 认参数 $.fn.pluginName.defaults = { text : "hello" }; })(jQuery); // $(".selector").pluginName({ // text : "Hello World!" // });

添加参数支持还比较容易些,又解决一问题

代码相对独立 链式操作 插件可配置 有可操作的方法插件的生命周期可控制 配置可被缓存 可扩展 无冲突处理 事件代理,动态初始化

插件的第三形态

现在来添加方法支持,我前面所提到的生命周期可控制,意思差不多,例如添加reInit,destory等方法来控制插件

代码如下:
一个参数是字符串,就查找是否存在该方法,找到就调用; 如果是object对象,就调用init方法;. if (methods[method]) { // 如果存在该方法调用方法 // apply 是吧 obj.method(arg1,arg2,arg3) 转换成 method(obj,[arg1,arg3]) 的过程. // Array.prototype.slice.call(arguments,1) 是把方法的参数转换成数组. return methods[method].apply(this,Array.prototype.slice.call(arguments,1)); } else if (typeof method === 'object' || !method) { // 如果传进来的参数是"{...}",就认为是初始化操作. return methods.init.apply(this,arguments); } else { $.error('Method ' + method + ' does not exist on jQuery.pluginName'); } }; // 不把方法扩展在 $.fn.pluginName 上. 在闭包内建个"methods"来保存方法,类似共有方法. var methods = { /** * 初始化方法 * @param _options * @return {*} */ init : function (_options) { return this.each(function () { var $this = $(this); var args = $.extend({},_options); // ... }) }, publicmethod : function(){ private_methods.demoMethod(); } }; // 私有方法 function private_methods = { demoMethod : function(){} } // 认参数 $.fn.pluginName.defaults = { }; })(jQuery); // 调用方式 // $("div").pluginName({...}); // 初始化 // $("div").pluginName("publicmethod"); // 调用方法

解决一问题

代码相对独立 链式操作 插件可配置 有可操作的方法插件的生命周期可控制 配置可被缓存 可扩展 无冲突处理 事件代理,动态初始化

插件的第四形态

第三形态的插件修改就已经可以应对大多数插件的需求了。精益求精嘛,继续升级。 第四形态的插件是照帮司徒正美的《javascript框架设计》的代码。加了点面向对象的知识。

代码如下:
在这里编写相应的代码进行处理 var ui = $._data(this,"pluginName"); // 如果该元素没有初始化过(可能是新添加的元素),就初始化它. if (!ui) { var opts = $.extend(true,{},typeof options === "object" ? options : {}); ui = new Plugin(this,opts); // 缓存插件 $._data(this,"pluginName",ui); } // 调用方法 if (typeof options === "string" && typeof ui[options] == "function") { // 执行插件方法 ui[options].apply(ui,args); } }); }; $.fn.pluginName.defaults = {}; })(jQuery); // 调用的方式和之前一样。

这里特别要提下缓存这个东西,插件用多了,觉的这个真的是好东西。 在传统面向对象的插件开发中,至少会声明个变量保存它,但是我到目前写的jQuery插件中都没有,用起来很麻烦。自从把初始化后的插件缓存起来后,方便了许多。通过代码$("#target").data("pluginName")就可以取到对象了。 来看看还有什么问题没有解决

代码相对独立 链式操作 插件可配置 有可操作的方法插件的生命周期可控制 配置可被缓存 可扩展 无冲突处理 事件代理,动态初始化

插件的第五形态

看了上面的代码是否脑子有点晕了,如果是,休息片刻,稍后回来,下面的代码更精彩。 最后一个方案算是比较全面的了。方案来自Bootstrap,下面代码以 Bootstrap 的 button 插件为例.

代码如下:
代码编写. "use strict"; // BUTTON PUBLIC CLASS DEFinitioN // ============================== 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 () { // ... }; // BUTTON PLUGIN DEFinitioN // ======================== var old = $.fn.button; // 这里的 $.fn.button 有可能是之前已经有定义过的插件在这里做无冲突处理使用。 $.fn.button = function (option) { return this.each(function () { var $this = $(this); // 判断是否初始化过的依据 var data = $this.data('bs.button'); var options = typeof option == 'object' && option; // 如果没有初始化过,就初始化它 if (!data) $this.data('bs.button',(data = new Button(this,options))); if (option == 'toggle') data.toggle(); else if (option) data.setState(option) }) }; // ① 暴露类名,可以通过这个为插件自定义扩展 $.fn.button.Constructor = Button; // 扩展的方式 // 设置 : $.fn.button.Constructor.newMethod = function(){} // 使用 : $btn.button("newMethod"); // ② 无冲突处理 $.fn.button.noConflict = function () { $.fn.button = old; return this }; // ③ 事件代理,智能初始化 $(document).on('click.bs.button.data-api','[data-toggle^=button]',function (e) { var $btn = $(e.target); // 查找要初始化的对象 if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn'); // 直接调用方法,如果没有初始化,内部会先进行初始化 $btn.button('toggle'); e.preventDefault(); }); }(jQuery);

来看看还有什么问题没有解决

代码相对独立 链式操作 插件可配置 有可操作的方法插件的生命周期可控制 配置可被缓存 可扩展 无冲突处理 事件代理,动态初始化

补充

现在的插件都要求灵活性要高,比如希望插件可以同时适配jQuery和Zepto,又或者需要支持AMD或者CMD规范。

支持jQuery和Zepto

代码如下:

中间件支持,node

代码如下:

呼~,问题都解决了,代码若有看不懂的地方可以多看看。后面的几个看不懂也没有关系,在实际的开发中,前面几个够用了。要强调下,并不是越高级的写法越好,要看自己项目的需求合理的选择。

好了,今天的总结就先到这里了,如果大家有更好的插件开发方式,还请告知一下。希望大家能够喜欢本文。

相关文章

页面搜索关键词突出 // 页面搜索关键词突出 $(function () {...
jQuery实时显示日期、时间 html: <span id=&quot...
jQuery 添加水印 <script src="../../../.....
中文:Sys.WebForms.PageRequestManagerParserErrorExceptio...
1. 用Response.Write方法 代码如下: Response.Write(&q...
Jquery实现按钮点击遮罩加载,处理完后恢复 思路: 1.点击按...