jQuery插件开发

前端开发所用浏览器
前端开发利用浏览器
前端开发用的谷歌浏览器版本

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

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

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

插件的第一形态

面对这种情况,通常我们会通过定义function的方式来实现。[code]function pluginName($selector){
$.each($selector, function () {
$(this).css(“background-color”, “#ccc”);
// to do something…
});
}
// pluginName(document.getElementsByClassName(“demo”));[/code]
因为我谈的是jquery插件开发,那么我现在把这段代码扩展到jquery上,代码如下[backcolor=rgb(247, 247, 247)][/bgcolor]
[code]// 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();[/code]
但是还差的远,目前只解决了两个问题

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

插件的第二形态
现在来给插件添加参数支持。代码如下[backcolor=rgb(247, 247, 247)][code];(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!”
// });[/code]

添加参数支持还比较容易些,又解决一问题
代码相对独立
链式操作
插件可配置
有可操作的方法,插件的生命周期可控制
配置可被缓存
可扩展
无冲突处理
事件代理,动态初始化

插件的第三形态
现在来添加方法的支持,我前面所提到的生命周期可控制,意思差不多,例如添加reInit,destory等方法来控制插件。
[backcolor=rgb(247, 247, 247)][code];(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”); // 调用方法[/code]
[/bgcolor]又解决一问题
[list=1]
[]代码相对独立
[
]链式操作
[]插件可配置
[
]有可操作的方法,插件的生命周期可控制
[]配置可被缓存
[
]可扩展
[]无冲突处理
[
]事件代理,动态初始化
[/list]
插件的第四形态
第三形态的插件修改就已经可以应对大多数插件的需求了。精益求精嘛,继续升级。
第四形态的插件是照帮司徒正美《javascript框架设计》的代码。加了点面向对象的知识。
[backcolor=rgb(247, 247, 247)][code](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);
// 调用的方式和之前一样。[/code][/bgcolor]
这里特别要提下缓存这个东西,插件用多了,觉的这个真的是好东西。
在传统面向对象的插件开发中,至少会声明个变量保存它,但是我到目前写的jQuery插件中都没有,用起来很麻烦。自从把初始化后的插件缓存起来后,方便了许多。通过代码$("#target").data("pluginName")就可以取到对象了。
来看看还有什么问题没有解决
[list=1]
[]代码相对独立
[
]链式操作
[]插件可配置
[
]有可操作的方法,插件的生命周期可控制
[]配置可被缓存
[
]可扩展
[]无冲突处理
[
]事件代理,动态初始化
[/list]
插件的第五形态
看了上面的代码是否脑子有点晕了,如果是,休息片刻,稍后回来,下面的代码更精彩。
最后一个方案算是比较全面的了。方案来自Bootstrap,下面代码以 Bootstrap 的 button 插件为例.
[code]!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);[/code]
哈哈,问题都解决了
[list=1]
[]代码相对独立
[
]链式操作
[]插件可配置
[
]有可操作的方法,插件的生命周期可控制
[]配置可被缓存
[
]可扩展
[]无冲突处理
[
]事件代理,动态初始化
[/list]

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

添加参数支持还比较容易些,又解决一问题
代码相对独立
链式操作
插件可配置
有可操作的方法,插件的生命周期可控制
配置可被缓存
可扩展
无冲突处理
事件代理,动态初始化[list]
支持jQuery和Zept[code]if (window.jQuery || window.Zepto) {
    (function ($) {
        // plugin code…
    })(window.jQuery || window.Zepto);
} [
    中间件支持,nod[code]if (typeof (module) !== ‘undefined’) {
    module.exports = pluginName;
} [
    支持 requirejs(AMD)[code]if (typeof define === ‘function’ && define.amd) {
        define(, function () {
            ‘use strict’;
            return pluginName;
        });
    } [
        支持 seajs(CMD)[code]if (typeof define === ‘function’) {
            define(, function () {
                ‘use strict’;
                return pluginName;
            });
        } [

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

前端开发浏览器兼容问题
前端开发时浏览器显示日志
各个浏览器 前端开发
» 本文来自:前端开发者 » 《jQuery插件开发》
» 本文链接地址:https://www.rokub.com/6528.html
» 您也可以订阅本站:https://www.rokub.com
赞(0)
64K

评论 抢沙发

评论前必须登录!