jQuery插件开发的五种形态[转]
这篇文章主要介绍了jQuery插件开发的五种形态小结,具体的内容就是解决javascript插件的8种特征,非常的详细。
关于jQuery插件的开发自己也做了少许研究,自己也写过多个插件,在自己的团队了也分享过一次关于插件的课。开始的时候整觉的很复杂的代码,现在再次看的时候就清晰了许多。这里我把我自己总结出来的东西分享出来,帮助那些和我一样曾经遇到过同样问题的人。
我要做什么
我想要得到的javascript 插件应该会有以下几个特征:
- [ ] 代码相对独立
- [ ] 链式操作
- [ ] 插件可配置
- [ ] 有可操作的方法,插件的生命周期可控制
- [ ] 配置可被缓存
- [ ] 可扩展
- [ ] 无冲突处理
- [ ] 事件代理,动态初始化
插件的第一形态
面对这种情况,通常我们会通过定义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();
但是还差的远,目前只解决了两个问题
- [x] 代码相对独立
- [x] 链式操作
- [ ] 插件可配置
- [ ] 有可操作的方法,插件的生命周期可控制
- [ ] 配置可被缓存
- [ ] 可扩展
- [ ] 无冲突处理
- [ ] 事件代理,动态初始化
插件的第二形态
现在来给插件添加参数支持。代码如下
;(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!"
// });
添加参数支持还比较容易些,又解决一问题
- [x] 代码相对独立
- [x] 链式操作
- [x] 插件可配置
- [ ] 有可操作的方法,插件的生命周期可控制
- [ ] 配置可被缓存
- [ ] 可扩展
- [ ] 无冲突处理
- [ ] 事件代理,动态初始化
插件的第三形态
现在来添加方法的支持,我前面所提到的生命周期可控制,意思差不多,例如添加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"); // 调用方法
又解决一问题
- [x] 代码相对独立
- [x] 链式操作
- [x] 插件可配置
- [x] 有可操作的方法,插件的生命周期可控制
- [ ] 配置可被缓存
- [ ] 可扩展
- [ ] 无冲突处理
- [ ] 事件代理,动态初始化
插件的第四形态
第三形态的插件修改就已经可以应对大多数插件的需求了。精益求精嘛,继续升级。
第四形态的插件是照帮司徒正美的《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")就可以取到对象了。 来看看还有什么问题没有解决
- [x] 代码相对独立
- [x] 链式操作
- [x] 插件可配置
- [x] 有可操作的方法,插件的生命周期可控制
- [x] 配置可被缓存
- [ ] 可扩展
- [ ] 无冲突处理
- [ ] 事件代理,动态初始化
插件的第五形态
看了上面的代码是否脑子有点晕了,如果是,休息片刻,稍后回来,下面的代码更精彩。 最后一个方案算是比较全面的了。方案来自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);
来看看还有什么问题没有解决
- [x] 代码相对独立
- [x] 链式操作
- [x] 插件可配置
- [x] 有可操作的方法,插件的生命周期可控制
- [x] 配置可被缓存
- [x] 可扩展
- [x] 无冲突处理
- [x] 事件代理,动态初始化
补充
现在的插件都要求灵活性要高,比如希望插件可以同时适配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插件开发的五种形态[转]的更多相关文章
- jQuery插件开发的五种形态小结(转)
关于jQuery插件的开发自己也做了少许研究,自己也写过多个插件,在自己的团队了也分享过一次关于插件的课.开始的时候整觉的很复杂的代码,现在再次看的时候就清晰了许多.这里我把我自己总结出来的东西分享出 ...
- jQuery插件开发的五种形态小结
关于jQuery插件的开发自己也做了少许研究,自己也写过多个插件,在自己的团队了也分享过一次关于插件的课.开始的时候整觉的很复杂的代码,现在再次看的时候就清晰了许多.这里我把我自己总结出来的东西分享出 ...
- jQuery插件开发的两种方法及$.fn.extend的详解
jQuery插件开发分为两种: 1 类级别 类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery.ex ...
- javascript笔记——jQuery插件开发的几种方式
jQuery插件开发分为两种: 1 类级别 类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery.e ...
- jQuery插件开发的两种方法及$.fn.extend的详解(转)
jQuery插件开发的两种方法及$.fn.extend的详解 jQuery插件开发分为两种:1 类级别.2 对象级别,下面为大家详细介绍下 jQuery插件开发分为两种: 1 类级别 类级别你可以 ...
- jQuery插件开发的两种方法
1 类级别 类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery.extend(object); $. ...
- jQuery插件开发中$.extend和$.fn.extend辨析
jQuery插件开发分为两种: 1 类级别 类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery. ...
- JavaScript学习总结(五)——jQuery插件开发与发布
jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...
- JavaScript学习总结(四)——jQuery插件开发与发布
jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...
随机推荐
- python subprocess 自动运行实验室程序
import threading, os, subprocess, time exec_path = "/home/xhz/gems/ruby/amd...../bin/tester.exe ...
- House Robber III leetcode 动态规划
https://leetcode.com/submissions/detail/56095603/ 这是一道不错的DP题!自己想了好久没有清晰的思路,参看大神博客!http://siukwan.sin ...
- 写在学AngularJS之前
近来从不同途径听说AngularJS和MEAN stack,感觉很有趣的样子,于是准备抽时间来学习一下.在这里记录学习过程中的笔记. 简单整理一下先: 1. 我的学习资料: a) 官网 b) wiki ...
- 一个好用的C#类型转换器
public static object ChangeType(object value, Type targetType) { if (targetType.IsGenericType && ...
- 学习django之正则表达式re模块
re(regular expression)模块 正则表达式(regular expression)主要功能是从字符串(string)中通过特定的模式(pattern),搜索想要找到的内容. 一.re ...
- PHP程序员如何突破技术瓶颈
身边有几个做PHP开发的朋友,也接触到不少的PHP工程师,他们常疑虑自己将来在技术上的成长与发展,我常给他们一些建议,希望他们能破突自己,有更好的发展. 先明确我所指的PHP工程题,是指毕业工作后,主 ...
- petapoco 使用 MiniProfiler Glimpse监控
PetaPoco是一款适用于.Net(window) 和Mono( linux )的微小.快速.单文件的微型ORM. MVC MiniProfiler是Stack Overflow团队设计的一款对AS ...
- 套题 codeforces 361
A题((Mike and Cellphone) 看起来好像需要模拟数字键位的运动,可是,只要判断出那些必然YES的数字组合不就好了么 #include <cstdio> #include ...
- gulp实用插件总结
gulp-sass:预编译sass; gulp-imagemin:压缩png.jpj.git.svg格式图片 gulp-minfy-css:压缩css文件 gulp-rename 重命名文件,把一个文 ...
- [poi2007] biu
题意:给定一个图,点n<=105,边m<=106,现在求它的补图有多少个联通分量.. 思路:很容易想到并查集,但是补图边太多了.. 于是只能优化掉一些多余的边.. 具体做法是用队列优化.. ...