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

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

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

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

插件的第一形态

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

复制代码代码如下:
function pluginName($selector){
    $.each($selector, function () {
        $(this).css("background-color", "#ccc");
        // to do something...
    });
}
// pluginName(document.getElementsByClassName("demo"));

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

复制代码代码如下:
// IIFE(立即调用函数表达式);  [参考 http://suqing.iteye.com/blog/1981591/]
;(function ($) {
    // 扩展这个方法到jQuery.
    // $.extend() 是吧方法扩展到 $ 对象上,和 $.fn.extend 不同。 扩展到 $.fn.xxx 上后,
    // 调用的时候就可以是 $(selector).xxx()
    $.fn.extend({
        // 插件名字
        pluginName: function () {
            // 遍历匹配元素的集合
            // 注意这里有个"return",作用是把处理后的对象返回,实现链式操作
            return this.each(function () {
                // 在这里编写相应的代码进行处理
            });
        }
    });
// 传递jQuery到内层作用域去, 如果window,document用的多的话, 也可以在这里传进去.
// })(jQuery, window, document, undefined);
})(jQuery, undefined);
// 调用方式 $(".selector").pluginName().otherMethod();

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

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

插件的第二形态

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

复制代码代码如下:
;(function($){
    $.fn.pluginName = function(options) {
        // 合并参数,通过“extend”合并默认参数和自定义参数
        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等方法来控制插件。

复制代码代码如下:
;(function($){
    $.fn.pluginName = function (method) {
        // 如果第一个参数是字符串, 就查找是否存在该方法, 找到就调用; 如果是object对象, 就调用init方法;.
        if (methods[method]) {
            // 如果存在该方法就调用该方法
            // apply 是吧 obj.method(arg1, arg2, arg3) 转换成 method(obj, [arg1, arg2, 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({}, $.fn.pluginName.defaults, _options);
                // ...
            })
        },
        publicMethod : function(){
            private_methods.demoMethod();
        }
    };
    // 私有方法
    function private_methods = {
        demoMethod : function(){}
    }
    // 默认参数
    $.fn.pluginName.defaults = {
    };
})(jQuery);
// 调用方式
// $("div").pluginName({...});  // 初始化
// $("div").pluginName("publicMethod");  // 调用方法

又解决一问题

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

插件的第四形态

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

复制代码代码如下:
(function ($) {
    var Plugin = function (element, options) {
        this.element = element;
        this.options = options;
    };
    Plugin.prototype = {
        create: function () {
            console.log(this.element);
            console.log(this.options);
        }
    };
    $.fn.pluginName = function (options) {
        // 合并参数
        return this.each(function () {
            // 在这里编写相应的代码进行处理
            var ui = $._data(this, "pluginName");
            // 如果该元素没有初始化过(可能是新添加的元素), 就初始化它.
            if (!ui) {
                var opts = $.extend(true, {}, $.fn.pluginName.defaults, 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 插件为例.

复制代码代码如下:
!function ($) {
    // ecma262v5 的新东西, 强制使用严谨的代码编写.
    "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

复制代码代码如下:
if (window.jQuery || window.Zepto) {
  (function ($) {
      // plugin code...
  })(window.jQuery || window.Zepto);
}

中间件支持,node

复制代码代码如下:
if (typeof(module) !== 'undefined')
{
  module.exports = pluginName;
}
requirejs(AMD) support
if (typeof define === 'function' && define.amd) {
  define([], function () {
      'use strict';
      return pluginName;
  });
}
seajs(CMD) support
if (typeof define === 'function') {
  define([], function () {
      'use strict';
      return pluginName;
  });
}

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

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

jQuery插件开发的五种形态小结(转)的更多相关文章

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

    关于jQuery插件的开发自己也做了少许研究,自己也写过多个插件,在自己的团队了也分享过一次关于插件的课.开始的时候整觉的很复杂的代码,现在再次看的时候就清晰了许多.这里我把我自己总结出来的东西分享出 ...

  2. jQuery插件开发的五种形态[转]

    这篇文章主要介绍了jQuery插件开发的五种形态小结,具体的内容就是解决javascript插件的8种特征,非常的详细. 关于jQuery插件的开发自己也做了少许研究,自己也写过多个插件,在自己的团队 ...

  3. jQuery插件开发的两种方法及$.fn.extend的详解

    jQuery插件开发分为两种: 1 类级别 类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery.ex ...

  4. javascript笔记——jQuery插件开发的几种方式

    jQuery插件开发分为两种: 1 类级别  类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery.e ...

  5. jQuery插件开发的两种方法及$.fn.extend的详解(转)

    jQuery插件开发的两种方法及$.fn.extend的详解 jQuery插件开发分为两种:1 类级别.2 对象级别,下面为大家详细介绍下   jQuery插件开发分为两种: 1 类级别 类级别你可以 ...

  6. C#后台调用前台javascript的五种方法小结

    第一种,OnClientClick (vs2003不支持这个方法) <asp:Button ID="Button1" runat="server" Tex ...

  7. jQuery插件开发的两种方法

    1 类级别 类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery.extend(object); $. ...

  8. jQuery插件开发中$.extend和$.fn.extend辨析

    jQuery插件开发分为两种:   1 类级别 类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery. ...

  9. JavaScript学习总结(五)——jQuery插件开发与发布

    jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...

随机推荐

  1. Latex "Error: File ended while scanning use of \@xdblarge"

    Latex 编译时出现 Error: File ended while scanning use of \@xdblarge" 是因为少了一个 }...

  2. [再寄小读者之数学篇](2015-06-24 Series)

    (AMM. Problems and Solutions. 2015. 03) Let $\sed{a_n}$ be a monotone decreasing sequence of real nu ...

  3. MySQL的一些基本命令笔记(4)

    delete 语句嵌套子查询: delete from 表名1 where 列名 操作符 (select 列名 from 表名2 where 条件); 示例: delete from customer ...

  4. notepad++ 代码注释快捷键

    在用notepad++进行代码编辑的过程中 单行.多行注释            //方式          :ctrl+k 取消单行.多行.区块注释                 :ctrl+sh ...

  5. HTTP协议11-cookie和seesion

    因为HTTP协议是无状态的,但是很多网站的功能需要先登录才能使用.这就引入了cookie. Cookie机制 服务器用HTTP头向客户端发送cookies.客户端(浏览器)解析cookies并将它们保 ...

  6. CVE_2012_1876堆溢出分析

    首先用windbg附加进程ie页面内容进程,!gflag +hpa添加堆尾检查,.childdbg 1允许子进程调试,然后加载POC. POC: <html> <body> & ...

  7. PHP生成HTML文件, SummerHtml

    2018-6-27 20:13:04 星期三 作用: 用PHP生成HTML文档, 支持标签嵌套缩进 起因: 这个东西确实也是心血来潮写的, 我很满意里边的实现缩进的机制, 大家有用到的可以看看 现在都 ...

  8. windows生成库文件

    库文件的生成,包括静态库lib与动态库dll,需要改变编译输出的生成命令,可以一开始生成对应的库工程(或者在工程属性->常规->配置类型更改). 附基本对应命令: gcc –c -L .o ...

  9. MS SQL Server 时间函数

    日期和时间数据类型 数据类型 存储(字节) 日期范围 精确度 格式示例 DateTime 8 1753年1月1日 - 9999年12月31日 3 1/3毫秒 yyyy-MM-dd hh:mm:ss.n ...

  10. java集合(list,set,map)

    集合 集合与数组 数组(可以存储基本数据类型)是用来存现对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用. 集合(只能存储对象,对象类型可以不一样)的长度可变,可在多数情况下使用. ...