有这么多人开发 jQuery 插件,遇到一个简单的 - 由于缺乏更好的语言 - 糟糕透顶的情况并不少见。没有示例或文档,该插件不遵循最佳实践等。但您是幸运者之一:本文将详细介绍您必须避免的陷阱。
对于那些经常使用 Nettuts+ 的人来说,jQuery 并不陌生。 Jeffrey Way 的《30 天学习 jQuery》(以及此处和其他地方的各种其他教程)很棒,带领我们所有人走上了 Sizzle 支持的 Awesomesauce 之路。在所有的炒作中(以及开发人员和浏览器供应商在 JavaScript 采用方面的巨大飞跃),大量的插件已经出现。这就是 jQuery 成为最流行的 JavaScript 库的部分原因!唯一的问题是其中许多都不是太好。
在本文中,我们将不再专门关注 JavaScript,而是更多地关注插件交付的最佳实践。
有一些模式或多或少被普遍认为是创建 jQuery 插件的“正确方法”。如果您不遵循这些约定,您的插件可能...很糟糕!考虑最常见的模式之一:
(function($, window, undefined){ $.fn.myPlugin = function(opts) { var defaults = { // setting your default values for options } // extend the options from defaults with user's options var options = $.extend(defaults, opts || {}); return this.each(function(){ // jQuery chainability // do plugin stuff }); })(jQuery, window);
首先,我们创建一个自调用匿名函数来避免使用全局变量。我们传入 $
、window
和 undefined
。调用自调用函数的参数是 jQuery
和 window
;没有为 undefined 传入任何内容,因此,如果我们决定在插件中使用 undefined 关键字,“undefined”实际上将是未定义的。
这可以防止其他脚本可能向
undefined
分配恶意值,例如true
!
$
作为 jQuery 传递;我们这样做是为了确保在匿名函数之外, $
仍然可以完全引用其他内容,例如 Prototype。
传递全局可访问的 window
对象的变量允许通过缩小过程(您也应该这样做)来压缩更多的代码。
接下来,我们使用 jQuery 插件模式,$.fn.PluginName
。这是注册插件以使用 $(selector).method()
格式的方法。它只是用您的新方法扩展了 jQuery 的原型。如果您想创建一个在 jQuery 对象上定义函数的插件,请直接添加它,如下所示:
$.PluginName = function(options){ // extend options, do plugin stuff }
这种类型的插件无法链接,因为定义为 jQuery 对象属性的函数通常不会返回 jQuery 对象。例如,考虑以下代码:
$.splitInHalf = function(stringToSplit){ var length = stringToSplit.length; var stringArray = stringToSplit.split(stringToSplit[Math.floor(length/2)]); return stringArray; }
在这里,我们返回一个字符串数组。简单地将其作为数组返回是有意义的,因为这可能是用户想要使用的(如果他们愿意,他们可以轻松地将其包装在 jQuery 对象中)。相反,请考虑以下人为的示例:
$.getOddEls = function(jQcollection){ // return jQcollection.filter(function(index){ var i = index+1; return (index % 2 != 0); }); }
在这种情况下,用户可能期望从 $.getOddEls
返回 jQuery 对象;因此,我们返回filter方法,该方法返回由传递的函数定义的jQuery集合。一个好的经验法则是将返回的元素包装在 jQuery 函数中,特别是如果它们可以链接起来;如果您要返回数组、字符串、数字、函数或其他数据类型,请将它们打开。
可以说,发布代码时可以做的最重要的事情就是添加必要的文档。您向开发人员解释的内容与代码实际执行或可以执行的操作之间的差距是用户不想浪费时间来弄清楚代码的来龙去脉。
文档是一种没有任何硬性规则的实践;但是,人们普遍认为拥有的(组织良好的)文档越多越好。
这个过程应该既是内部实践(在代码中/散布在整个代码中),也是外部实践(在 wiki 或自述文件中彻底解释每个公共方法、选项和多个用例)。
最流行的插件提供对用户可能想要控制的变量(大多数插件称为“选项”对象)的完全访问。他们还可能提供插件的许多不同配置,以便它可以在许多不同的上下文中重用。例如,让我们考虑一个简单的滑块插件。用户可能希望控制的选项包括动画的速度、类型和延迟。
最好还让用户访问添加到插件插入或操作的 DOM 元素中的类名/ID 名称。但除此之外,他们可能还希望在每次幻灯片转换时,或者当幻灯片转换回开头(一个完整的“循环”)时访问回调函数。
您的工作是考虑插件的所有可能用途和需求。
让我们考虑另一个例子:调用 API 的插件应该提供对 API 返回对象的访问。以下面的简单插件概念为例:
$.fn.getFlickr = function(opts) { return this.each(function(){ // jQuery chainability var defaults = { // setting your default options cb : function(data){}, flickrUrl : // some default value for an API call } // extend the options from defaults with user's options var options = $.extend(defaults, opts || {}); // call the async function and then call the callback // passing in the api object that was returned $.ajax(flickrUrl, function(dataReturned){ options.cb.call(this, dataReturned); }); }); }
这使我们能够做以下事情:
$(selector).getFlickr(function(fdata){ // flickr data is in the fdata object });
宣传这一点的另一种方式是提供“钩子”作为选项。从 jQuery 1.7.1 及更高版本开始,我们可以在插件调用之后使用 .on(eventName, function(){})
将行为分离到它们自己的函数中。例如,使用上面的插件,我们可以将代码更改为如下所示:
$.fn.getFlickr = function(opts) { return this.each(function(i,el){ var $this = el; var defaults = { // setting your default options flickrUrl : "http://someurl.com" // some default value for an API call } var options = $.extend(defaults, opts || {}); // call the async function and then call the callback // passing in the api object that was returned $.ajax(flickrUrl, function(dataReturned){ // do some stuff $this.trigger("callback", dataReturned); }).error(function(){ $this.trigger("error", dataReturned); }); }); }
这允许我们调用 getFlickr
插件并链接其他行为处理程序。
$(selector).getFlickr(opts).on("callback", function(data){ // do stuff }).on("error", function(){ // handle an error });
您可以看到提供这种灵活性绝对重要;您的插件的操作越复杂,可用的控件就越复杂。
好的,第三条建议是,您的插件的操作越复杂,可用的控制就越复杂。可用。然而,一个很大的错误是为插件功能提供了太多的选项。例如,基于 UI 的插件最好具有无参数默认行为。
$(selector).myPlugin();
当然,有时这是不现实的(例如,用户可能正在获取特定的提要)。在这种情况下,您应该为他们做一些繁重的工作。有多种方式将选项传递给插件。例如,假设我们有一个简单的推文获取器插件。该推文获取器应该有一个默认行为,带有一个必需选项(您要从中获取的用户名)。
$(selector).fetchTweets("jcutrell");
例如,默认情况下可能会抓取一条推文,将其包装在段落标记中,然后使用该 html 填充选择器元素。这是大多数开发人员所期望和欣赏的行为。细粒度选项应该就是:选项。
当然,根据插件的类型,如果高度基于 UI 操作,则必须包含 CSS 文件,这是不可避免的。一般来说,这是一个可以接受的问题解决方案;大多数插件都与图像和 CSS 捆绑在一起。但不要忘记第二点 - 文档还应包括如何使用/引用样式表和图像。开发人员不想浪费时间查看源代码来弄清楚这些事情。
事情应该只是......工作。
话虽如此,使用注入样式(可以通过插件选项高度访问)或基于类/ID 的样式绝对是最佳实践。这些 ID 和类也应该可以通过前面提到的选项进行访问。然而,内联样式会覆盖外部 CSS 规则;不鼓励将两者混合使用,因为开发人员可能需要很长时间才能弄清楚为什么插件创建的元素不遵守他们的 CSS 规则。在这些情况下请运用您的最佳判断。
根据经验,内联 CSS 很糟糕 - 除非它很小到无法保证有自己的外部样式表。
证据就在布丁中:如果您无法提供一个实际示例来说明您的插件如何使用随附的代码,人们很快就会放弃使用您的插件。就那么简单。不要偷懒。
一个很好的示例模板:
jQuery,像任何优秀的代码库一样,随着每个版本的发布而成长。即使在弃用支持后,大多数方法仍会保留。然而,添加了新的方法;一个完美的例子是 .on()
方法,它是 jQuery 的新的事件委托一体化解决方案。如果您编写一个使用 .on()
的插件,那么使用 jQuery 1.6 或更早版本的人将不走运。现在,我并不是建议您针对最低公分母进行编码,但是,在您的文档中,请务必解释您的插件支持哪个版本的 jQuery。如果您引入了支持 jQuery 1.7 的插件,那么即使 1.8 发布,您也应该强烈考虑维持对 1.7 的支持。您还应该考虑利用 jQuery 中新的/更好的/更快的功能。
鼓励开发人员升级,但不要太频繁地破坏您的插件!一种选择是提供插件的“旧版”、已弃用、不受支持的版本。
如果您还没有学会如何使用版本控制,那么是时候咬紧牙关了。
除了将 jQuery 版本支持/兼容性作为文档的一部分之外,您还应该进行版本控制。版本控制(具体来说,通过 GitHub)在很大程度上是社交编码的发源地。如果您正在开发一个 jQuery 插件并希望最终发布到官方存储库中,那么无论如何它都必须存储在 GitHub 存储库中;如果您还没有学会如何使用版本控制,那么是时候硬着头皮了。版本控制有无数的好处,所有这些都超出了本文的范围。但核心好处之一是,它允许人们查看您所做的更改、改进和兼容性修复以及您何时进行这些更改、改进和兼容性修复。这也为您编写的插件的贡献和定制/扩展打开了大门。
世界不需要另一个滑块插件。
好吧,我们在这里忽略它已经足够长的时间了:一些“插件”是无用的或太浅,不足以保证被称为插件。世界不需要另一个滑块插件!然而,应该指出的是,内部团队可能会开发自己的插件供自己使用,这是完全可以的。但是,如果您希望将您的插件推向社交编码领域,请找到编写更多代码的理由。俗话说,没有理由重新发明轮子。相反,接过别人的方向盘,建造一辆赛车。当然,有时会有新的、更好的方法来做已经做过的同样的事情。例如,如果您使用更快或新技术,您很可能会编写一个新的滑块插件。
这个相当简单:提供代码的缩小版本。这使得它更小、更快。它还确保您的 Javascript 在编译时不会出现错误。当您缩小代码时,不要忘记也提供未压缩的版本,以便您的同行可以查看底层代码。对于各种经验水平的前端开发人员来说,都有免费且廉价的工具。
有关自动化解决方案,请参阅提示十三。
当你编写一个插件时,它的目的就是供其他人使用,对吗?因此,最有效的源代码是具有高度可读性的。如果您正在编写无数巧妙的单行 lambda 样式函数,或者您的变量名称没有语义,那么当错误不可避免地发生时,将很难对其进行调试。不要编写短变量名来节省空间,而是遵循技巧九(缩小!)中的建议。这是优秀文档的另一部分;优秀的开发人员应该能够检查您的代码并了解其用途,而无需花费太多精力。
如果您发现自己调用变量“
a
”或“x
”,那么您就做错了。
此外,如果您发现自己查阅文档来记住您自己的看起来奇怪的代码正在做什么,那么您也可能需要不那么简洁并更具解释性。将每个函数的行数限制为尽可能少;如果它们延伸三十行或更多行,则可能会有代码味道。
尽管我们都喜欢使用 jQuery,但重要的是要了解它是一个库,而且成本很小。一般来说,您不需要太担心 jQuery 选择器性能之类的事情。不要令人讨厌,你会没事的。 jQuery 是高度优化的。也就是说,如果您需要 jQuery(或插件)的唯一原因是在 DOM 上执行一些查询,您可能会考虑完全删除抽象,而坚持使用普通 JavaScript 或 Zepto。
注意:如果您决定坚持使用普通 JavaScript,请确保您使用的是跨浏览器的方法。对于较新的 API,您可能需要一个小型的 polyfill。
使用咕噜声。期间。
Grunt 是一个“用于 JavaScript 项目的基于任务的命令行构建工具”,最近在 Nettuts+ 上对此进行了详细介绍。它允许你做这样的事情:
grunt init:jquery
此行(在命令行中执行)将提示您一系列问题,例如标题、描述、版本、git 存储库、许可证等。这些信息有助于自动化设置文档、许可等的过程。
Grunt 所做的不仅仅是为您制作一些定制的样板代码;它还提供内置工具,例如代码 linter JSHint,只要您安装了 PhantomJS(由 Grunt 负责),它就可以为您自动执行 QUnit 测试。这样,您可以简化工作流程,因为测试在保存时会立即在终端中运行。
哦,顺便说一下 - 你确实测试了你的代码,对吧?如果不是,您如何确保/声明您的代码按预期工作?手动测试有其一席之地,但是,如果您发现自己每小时无数次刷新浏览器,那么您就做错了。考虑使用 QUnit、Jasmine 甚至 Mocha 等工具。
在 GitHub 上合并拉取请求时,测试特别有用。您可以要求所有请求提供测试,以确保新的/修改的代码不会破坏您现有的插件。
如果测试 jQuery 插件的概念对您来说是全新的,请考虑观看我们的 Premium 独家截屏视频,测试驱动 jQuery 插件的技术。此外,我们将于本周晚些时候在网站上推出新的“使用 Jasmine 进行 JavaScript 测试”课程!
仅仅告诉您做错了什么,我们不会给您带来任何好处。这里有一些链接可以帮助您回到正确的道路!
如果您正在编写 jQuery 插件,那么远离上面列出的陷阱至关重要。我是否错过了插件执行不当的任何关键迹象?
以上是jQuery 插件未使用的 14 种可能解释的详细内容。更多信息请关注PHP中文网其他相关文章!