Ed *_*d . 59 javascript jquery jquery-plugins
我已经开始编写一些jQuery插件,并认为使用jQuery插件模板设置我的IDE会很不错.
我一直在阅读本网站上有关插件约定,设计等方面的一些文章和帖子.并且我认为我会尝试并巩固所有这些.
下面是我的模板,我希望经常使用它,所以很想确保它通常符合jQuery插件设计约定,以及是否有多个内部方法(甚至其一般设计)的想法会影响性能并容易出现内存问题.
(function($)
{
var PLUGIN_NAME = "myPlugin"; // TODO: Plugin name goes here.
var DEFAULT_OPTIONS =
{
// TODO: Default options for plugin.
};
var pluginInstanceIdCount = 0;
var I = function(/*HTMLElement*/ element)
{
return new Internal(element);
};
var Internal = function(/*HTMLElement*/ element)
{
this.$elem = $(element);
this.elem = element;
this.data = this.getData();
// Shorthand accessors to data entries:
this.id = this.data.id;
this.options = this.data.options;
};
/**
* Initialises the plugin.
*/
Internal.prototype.init = function(/*Object*/ customOptions)
{
var data = this.getData();
if (!data.initialised)
{
data.initialised = true;
data.options = $.extend(DEFAULT_OPTIONS, customOptions);
// TODO: Set default data plugin variables.
// TODO: Call custom internal methods to intialise your plugin.
}
};
/**
* Returns the data for relevant for this plugin
* while also setting the ID for this plugin instance
* if this is a new instance.
*/
Internal.prototype.getData = function()
{
if (!this.$elem.data(PLUGIN_NAME))
{
this.$elem.data(PLUGIN_NAME, {
id : pluginInstanceIdCount++,
initialised : false
});
}
return this.$elem.data(PLUGIN_NAME);
};
// TODO: Add additional internal methods here, e.g. Internal.prototype.<myPrivMethod> = function(){...}
/**
* Returns the event namespace for this widget.
* The returned namespace is unique for this widget
* since it could bind listeners to other elements
* on the page or the window.
*/
Internal.prototype.getEventNs = function(/*boolean*/ includeDot)
{
return (includeDot !== false ? "." : "") + PLUGIN_NAME + "_" + this.id;
};
/**
* Removes all event listeners, data and
* HTML elements automatically created.
*/
Internal.prototype.destroy = function()
{
this.$elem.unbind(this.getEventNs());
this.$elem.removeData(PLUGIN_NAME);
// TODO: Unbind listeners attached to other elements of the page and window.
};
var publicMethods =
{
init : function(/*Object*/ customOptions)
{
return this.each(function()
{
I(this).init(customOptions);
});
},
destroy : function()
{
return this.each(function()
{
I(this).destroy();
});
}
// TODO: Add additional public methods here.
};
$.fn[PLUGIN_NAME] = function(/*String|Object*/ methodOrOptions)
{
if (!methodOrOptions || typeof methodOrOptions == "object")
{
return publicMethods.init.call(this, methodOrOptions);
}
else if (publicMethods[methodOrOptions])
{
var args = Array.prototype.slice.call(arguments, 1);
return publicMethods[methodOrOptions].apply(this, args);
}
else
{
$.error("Method '" + methodOrOptions + "' doesn't exist for " + PLUGIN_NAME + " plugin");
}
};
})(jQuery);
Run Code Online (Sandbox Code Playgroud)
提前致谢.
Kee*_*ker 28
前段时间我根据我读过的博客文章构建了一个插件生成器:http://jsfiddle.net/KeesCBakker/QkPBF/.它可能有用.这是相当基本和直接的.任何评论都会非常受欢迎.
您可以分叉自己的发电机并根据需要进行更改.
PS.这是生成的主体:
(function($){
//My description
function MyPluginClassName(el, options) {
//Defaults:
this.defaults = {
defaultStringSetting: 'Hello World',
defaultIntSetting: 1
};
//Extending options:
this.opts = $.extend({}, this.defaults, options);
//Privates:
this.$el = $(el);
}
// Separate functionality from object creation
MyPluginClassName.prototype = {
init: function() {
var _this = this;
},
//My method description
myMethod: function() {
var _this = this;
}
};
// The actual plugin
$.fn.myPluginClassName = function(options) {
if(this.length) {
this.each(function() {
var rev = new MyPluginClassName(this, options);
rev.init();
$(this).data('myPluginClassName', rev);
});
}
};
})(jQuery);
Run Code Online (Sandbox Code Playgroud)
Ray*_*nos 26
[编辑] 7个月后
引用github项目
jQuery并不好,而jQuery插件不是模块化代码怎么做的.
严重的"jQuery插件"不是一个健全的架构策略.编写对jQuery具有硬依赖性的代码也很愚蠢.
[原版的]
由于我对这个模板提出了批评,我将提出一个替代方案.
为了让生活更轻松,这依赖于jQuery1.6+和ES5(使用ES5 Shim).
我花了一些时间重新设计你给出的插件模板并推出了我自己的插件模板.
链接:
比较:
我重构了模板,以便将它分成样板(85%)和脚手架代码(15%).目的是您只需编辑脚手架代码,并且可以保持样板代码不变.为了达到这个目的,我已经习惯了
var self = Object.create(Base)而不是Internal直接编辑你的类,你应该编辑一个子类.您的所有模板/默认功能都应该在基类中(Base在我的代码中调用).self[PLUGIN_NAME] = main;按照惯例,jQuery上定义的插件self[PLUGIN_NAME]默认会调用方法define on .这被认为是main插件方法,并且为了清楚起见具有单独的外部方法.$.fn.bind = function _bind ...使用猴子修补意味着事件命名空间是在引擎盖下自动完成的.此功能是免费的,不会以可读性为代价(一直调用getEventNS).OO技术
最好坚持使用适当的JavaScript OO,而不是经典的OO仿真.要实现这一点,你应该使用Object.create.(ES5只使用垫片升级旧浏览器).
var Base = (function _Base() {
var self = Object.create({});
/* ... */
return self;
})();
var Wrap = (function _Wrap() {
var self = Object.create(Base);
/* ... */
return self;
})();
var w = Object.create(Wrap);
Run Code Online (Sandbox Code Playgroud)
这与标准new和.prototype基于OO的人习惯不同.这种方法是首选,因为它重新强化了JavaScript中只有对象的概念,它是一种典型的面向对象方法.
[ getEventNs]
如前所述,此方法已通过重写.bind和.unbind自动注入名称空间进行了重构.这些方法在私有版本的jQuery上被覆盖$.sub().覆盖的方法与命名空间的行为方式相同.它根据插件和HTMLElement周围的插件包装器实例独特地命名事件(使用.ns.
[ getData]
此方法已替换为.data具有相同API的方法jQuery.fn.data.事实上它是相同的API使它更容易使用,它基本上是一个jQuery.fn.data使用命名空间的薄包装.这允许您设置仅为该插件存储的键/值对数据.多个插件可以并行使用此方法而不会发生任何冲突.
[ publicMethods]
publicMethods对象已Wrap被自动公开时定义的任何方法所取代.您可以直接调用Wrapped对象上的任何方法,但实际上您无法访问包装对象.
[ $.fn[PLUGIN_NAME]]
这已被重构,因此它暴露了更标准化的API.这个api是
$(selector).PLUGIN_NAME("methodName", {/* object hash */}); // OR
$(selector).PLUGIN_NAME({/* object hash */}); // methodName defaults to PLUGIN_NAME
Run Code Online (Sandbox Code Playgroud)
选择器中的元素自动包装在Wrap对象中,调用方法或选择器中的每个选定元素,返回值始终是$.Deferred元素.
这标准化了API和返回类型.然后,您可以调用.then返回的延迟来获取您关心的实际数据.这里使用deferred非常强大,可以抽象出插件是同步还是异步.
添加了缓存创建功能.这被称为将a HTMLElement变成Wrapped元素,每个HTMLElement只会被包装一次.这种缓存可以大大减少内存.
为插件添加了另一个公共方法(总共两个!).
$.PLUGIN_NAME(elem, "methodName", {/* options */});
$.PLUGIN_NAME([elem, elem2, ...], "methodName", {/* options */});
$.PLUGIN_NAME("methodName", {
elem: elem, /* [elem, elem2, ...] */
cb: function() { /* success callback */ }
/* further options */
});
Run Code Online (Sandbox Code Playgroud)
所有参数都是可选的.elem默认为<body>,"methodName"默认为"PLUGIN_NAME"和{/* options */}默认为{}.
这个API非常灵活(有14个方法重载!)和足够的标准,可以适应你的插件将公开的每个方法的syntnax.
的Wrap,create而$对象是全球范围内曝光.这将允许高级插件用户使用您的插件获得最大的灵活性.他们可以在他们的开发中使用create和修改的subbed $他们也可以猴子补丁Wrap.这允许挂钩你的插件方法.所有这三个都_在他们的名字前面标记,所以他们是内部的,使用它们打破你的插件工作的garantuee.
内部defaults对象也公开为$.PLUGIN_NAME.global.这允许用户覆盖您的默认值并设置插件全局defaults.在此插件设置中,当对象与默认值合并时,所有哈希都会进入方法,因此这允许用户为所有方法设置全局默认值.
(function($, jQuery, window, document, undefined) {
var PLUGIN_NAME = "Identity";
// default options hash.
var defaults = {
// TODO: Add defaults
};
// -------------------------------
// -------- BOILERPLATE ----------
// -------------------------------
var toString = Object.prototype.toString,
// uid for elements
uuid = 0,
Wrap, Base, create, main;
(function _boilerplate() {
// over-ride bind so it uses a namespace by default
// namespace is PLUGIN_NAME_<uid>
$.fn.bind = function _bind(type, data, fn, nsKey) {
if (typeof type === "object") {
for (var key in type) {
nsKey = key + this.data(PLUGIN_NAME)._ns;
this.bind(nsKey, data, type[key], fn);
}
return this;
}
nsKey = type + this.data(PLUGIN_NAME)._ns;
return jQuery.fn.bind.call(this, nsKey, data, fn);
};
// override unbind so it uses a namespace by default.
// add new override. .unbind() with 0 arguments unbinds all methods
// for that element for this plugin. i.e. calls .unbind(_ns)
$.fn.unbind = function _unbind(type, fn, nsKey) {
// Handle object literals
if ( typeof type === "object" && !type.preventDefault ) {
for ( var key in type ) {
nsKey = key + this.data(PLUGIN_NAME)._ns;
this.unbind(nsKey, type[key]);
}
} else if (arguments.length === 0) {
return jQuery.fn.unbind.call(this, this.data(PLUGIN_NAME)._ns);
} else {
nsKey = type + this.data(PLUGIN_NAME)._ns;
return jQuery.fn.unbind.call(this, nsKey, fn);
}
return this;
};
// Creates a new Wrapped element. This is cached. One wrapped element
// per HTMLElement. Uses data-PLUGIN_NAME-cache as key and
// creates one if not exists.
create = (function _cache_create() {
function _factory(elem) {
return Object.create(Wrap, {
"elem": {value: elem},
"$elem": {value: $(elem)},
"uid": {value: ++uuid}
});
}
var uid = 0;
var cache = {};
return function _cache(elem) {
var key = "";
for (var k in cache) {
if (cache[k].elem == elem) {
key = k;
break;
}
}
if (key === "") {
cache[PLUGIN_NAME + "_" + ++uid] = _factory(elem);
key = PLUGIN_NAME + "_" + uid;
}
return cache[key]._init();
};
}());
// Base object which every Wrap inherits from
Base = (function _Base() {
var self = Object.create({});
// destroy method. unbinds, removes data
self.destroy = function _destroy() {
if (this._alive) {
this.$elem.unbind();
this.$elem.removeData(PLUGIN_NAME);
this._alive = false;
}
};
// initializes the namespace and stores it on the elem.
self._init = function _init() {
if (!this._alive) {
this._ns = "." + PLUGIN_NAME + "_" + this.uid;
this.data("_ns", this._ns);
this._alive = true;
}
return this;
};
// returns data thats stored on the elem under the plugin.
self.data = function _data(name, value) {
var $elem = this.$elem, data;
if (name === undefined) {
return $elem.data(PLUGIN_NAME);
} else if (typeof name === "object") {
data = $elem.data(PLUGIN_NAME) || {};
for (var k in name) {
data[k] = name[k];
}
$elem.data(PLUGIN_NAME, data);
} else if (arguments.length === 1) {
return ($elem.data(PLUGIN_NAME) || {})[name];
} else {
data = $elem.data(PLUGIN_NAME) || {};
data[name] = value;
$elem.data(PLUGIN_NAME, data);
}
};
return self;
})();
// Call methods directly. $.PLUGIN_NAME(elem, "method", option_hash)
var methods = jQuery[PLUGIN_NAME] = function _methods(elem, op, hash) {
if (typeof elem === "string") {
hash = op || {};
op = elem;
elem = hash.elem;
} else if ((elem && elem.nodeType) || Array.isArray(elem)) {
if (typeof op !== "string") {
hash = op;
op = null;
}
} else {
hash = elem || {};
elem = hash.elem;
}
hash = hash || {}
op = op || PLUGIN_NAME;
elem = elem || document.body;
if (Array.isArray(elem)) {
var defs = elem.map(function(val) {
return create(val)[op](hash);
});
} else {
var defs = [create(elem)[op](hash)];
}
return $.when.apply($, defs).then(hash.cb);
};
// expose publicly.
Object.defineProperties(methods, {
"_Wrap": {
"get": function() { return Wrap; },
"set": function(v) { Wrap = v; }
},
"_create":{
value: create
},
"_$": {
value: $
},
"global": {
"get": function() { return defaults; },
"set": function(v) { defaults = v; }
}
});
// main plugin. $(selector).PLUGIN_NAME("method", option_hash)
jQuery.fn[PLUGIN_NAME] = function _main(op, hash) {
if (typeof op === "object" || !op) {
hash = op;
op = null;
}
op = op || PLUGIN_NAME;
hash = hash || {};
// map the elements to deferreds.
var defs = this.map(function _map() {
return create(this)[op](hash);
}).toArray();
// call the cb when were done and return the deffered.
return $.when.apply($, defs).then(hash.cb);
};
}());
// -------------------------------
// --------- YOUR CODE -----------
// -------------------------------
main = function _main(options) {
this.options = options = $.extend(true, defaults, options);
var def = $.Deferred();
// Identity returns this & the $elem.
// TODO: Replace with custom logic
def.resolve([this, this.elem]);
return def;
}
Wrap = (function() {
var self = Object.create(Base);
var $destroy = self.destroy;
self.destroy = function _destroy() {
delete this.options;
// custom destruction logic
// remove elements and other events / data not stored on .$elem
$destroy.apply(this, arguments);
};
// set the main PLUGIN_NAME method to be main.
self[PLUGIN_NAME] = main;
// TODO: Add custom logic for public methods
return self;
}());
})(jQuery.sub(), jQuery, this, document);
Run Code Online (Sandbox Code Playgroud)
可以看出,您应该编辑的代码位于该YOUR CODE行下方.该Wrap对象的行为与您的Internal对象类似.
该函数main是带有$.PLUGIN_NAME()或者$(selector).PLUGIN_NAME()应该包含主逻辑的主函数.
| 归档时间: |
|
| 查看次数: |
16352 次 |
| 最近记录: |