如何创建一个基本JQuery的插件
2021-06-09 04:13
链接提供公共访问默认插件设置
我们可以而且应该对上面的代码进行改进是公开默认的插件设置。这很重要,因为它使插件用户很容易用最小的代码覆盖/定制插件。这就是我们开始利用函数对象的地方。
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
|
// Plugin definition. $.fn.hilight = function( options ) { // Extend our default options with those provided. // Note that the first argument to extend is an empty // object – this is to keep from overriding our "defaults" object. var opts = $.extend( {}, $.fn.hilight.defaults, options ); // Our plugin implementation code goes here. }; // Plugin defaults – added as a property on our plugin function. $.fn.hilight.defaults = { foreground: "red", background: "yellow" }; |
现在,用户可以在脚本中包含这样一行:
1
2
3
|
// This needs only be called once and does not // have to be called from within a "ready" block $.fn.hilight.defaults.foreground = "blue"; |
现在我们可以像这样调用插件方法,它将使用蓝色的前景色:
1
|
$( "#myDiv" ).hilight(); |
您可以看到,我们允许用户编写一行代码来更改插件的默认前景色。而用户仍然可以选择性地覆盖这个新的默认值:
1
2
3
4
五
6
7
8
9
10
11
12
13
14
|
// Override plugin default foreground color. $.fn.hilight.defaults.foreground = "blue"; // ... // Invoke plugin using new defaults. $( ".hilightDiv" ).hilight(); // ... // Override default by passing options to plugin method. $( "#green" ).hilight({ foreground: "green" }); |
链接提供公共访问次要功能作为适用
该项目与上一个项目紧密相关,是扩展插件(并允许其他扩展插件)的有趣方式。例如,我们的插件的实现可以定义一个称为“格式”的功能,其格式化高亮文本。我们的插件可能看起来像这样,默认实现的格式方法定义在hilight函数下面:
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
// Plugin definition. $.fn.hilight = function( options ) { // Iterate and reformat each matched element. return this.each(function() { var elem = $( this ); // ... var markup = elem.html(); // Call our format function. markup = $.fn.hilight.format( markup ); elem.html( markup ); }); }; // Define our format function. $.fn.hilight.format = function( txt ) { return "" + txt + ""; }; |
我们可以轻松地支持选项对象上的另一个属性,允许提供回调函数来覆盖默认格式。这是支持自定义插件的另一个很好的方法。这里显示的技术通过实际暴露格式功能使其可以重新定义,从而进一步扩展。使用这种技术,其他人可能会发布自己的插件自定义覆盖 - 换句话说,这意味着其他人可以为插件编写插件。
考虑到我们在本文中构建的简单的示例插件,您可能会想知道何时会有用。一个现实世界的例子是循环插件。循环插件是一个幻灯片插件,它支持多种内置的转换效果 - 滚动,滑动,淡入淡出等。但是,实际上,没有办法定义可能希望应用于幻灯片转换的每种类型的效果。这就是这种类型的可扩展性是有用的。循环插件公开了一个“transition”对象,用户可以添加自己的自定义转换定义。它在插件中定义如下:
1
2
3
4
五
|
$.fn.cycle.transitions = { // ... }; |
这种技术使得其他人可以定义和提供插件到循环插件的转换定义。
链接保持私人功能私有
暴露部分插件被覆盖的技术可以非常强大。但是,您需要仔细考虑实施的哪些部分才能公开。一旦暴露,您需要记住,调用参数或语义的任何更改可能会破坏向后兼容性。作为一般规则,如果您不确定是否公开特定功能,那么您可能不应该。
那么,我们如何定义更多的功能,而不会混淆命名空间,而不会暴露实现?这是关闭的工作。为了演示,我们将在我们的插件中添加另一个函数叫做“debug”。调试功能将所选元素的数量记录到控制台。要创建一个闭包,我们将整个插件定义包装在一个函数中(如jQuery创作指南中所详述的)。
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// Create closure. (function( $ ) { // Plugin definition. $.fn.hilight = function( options ) { debug( this ); // ... }; // Private function for debugging. function debug( obj ) { if ( window.console && window.console.log ) { window.console.log( "hilight selection count: " + obj.length ); } }; // ... // End of closure. })( jQuery ); |
我们的“调试”方法无法从关闭的外部访问,因此对我们的实现是私有的。
链接Bob和Sue
假设鲍勃创建了一个邪恶的新画廊插件(称为“超级画廊”),其中包含一幅图像列表,并使其可导航。鲍勃抛出了一些动画,使它更有趣。他试图使插件尽可能的自定义,最终结果是这样的:
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
|
jQuery.fn.superGallery = function( options ) { // Bob‘s default settings: var defaults = { textColor: "#000", backgroundColor: "#fff", fontSize: "1em", delay: "quite long", getTextFromTitle: true, getTextFromRel: false, getTextFromAlt: false, animateWidth: true, animateOpacity: true, animateHeight: true, animationDuration: 500, clickImgToGoToNext: true, clickImgToGoToLast: false, nextButtonText: "next", previousButtonText: "previous", nextButtonTextColor: "red", previousButtonTextColor: "red" }; var settings = $.extend( {}, defaults, options ); return this.each(function() { // Plugin code would go here... }); }; |
第一件事可能是你的头脑(好的,也许不是第一个),这个插件必须有多大,以适应这样一个级别的定制。插件,如果不是虚构的,可能会比必要的大得多。只有这么多千字节的人会愿意花费!
现在,我们的朋友鲍勃认为这一切都很好; 事实上,他对插件及其定制级别印象深刻。他认为,所有的选择都可以使用更为通用的解决方案,可以在许多不同的情况下使用。
苏,我们的另一个朋友,决定使用这个新的插件。她已经设置了所有的选项,现在有一个工作的方案坐在她面前。只有五分钟后,玩插件后,如果每张图片的宽度都以较慢的速度动画,她意识到画廊会更好看。她匆忙搜索Bob的文档,但没有发现animateWidthDuration选项!
链接你看到问题吗?
这不是真的关于您的插件有多少选项; 但它有什么选择!
鲍勃已经超过了顶峰。他提供的定制水平虽然可能高,但实际上相当低,特别是考虑到使用此插件时可能需要控制的所有可能的事情。鲍勃犯了错误提供了很多可笑的具体选择,使他的插件更难以自定义!
链接更好的模型
所以很明显:鲍勃需要一个新的定制模式,一个不放弃控制或抽出必要细节的模型。
鲍勃如此吸引这个高级简单性的原因是,jQuery框架非常适合于这种观念。提供一个previousButtonTextColor选项是好的和简单的,但让我们面对它,绝大多数的插件用户将要更多的控制!
以下是一些提示,可帮助您为插件创建更好的可定制选项:
链接不要创建特定于插件的语法
使用您的插件的开发人员不应该学习一种新的语言或术语,只是为了完成这项工作。
鲍勃认为他提供最大的定制与他的延迟选项(看上面)。他做的这样,他的插件可以指定四个不同的延迟,“很短”,“很短”,“相当长”或“很长”:
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
var delayDuration = 0; switch ( settings.delay ) { case "very short": delayDuration = 100; break; case "quite short": delayDuration = 200; break; case "quite long": delayDuration = 300; break; case "very long": delayDuration = 400; break; default: delayDuration = 200; } |
这不仅限制了人们的控制水平,而且占用了相当多的空间。十二行代码只是为了定义延迟时间有点多,你不觉得吗?构建此选项的更好方法是让插件用户以数字的形式指定时间(以毫秒为单位),以便不需要处理该选项。
这里的关键不在于通过抽象来减少控制的程度。您的抽象,无论如何,可以像您想要的一样简单,但确保使用您的插件的人仍然会有这么多追捧的低级控制!(低级我的意思是非抽象的)
链接充分控制元素
如果您的插件创建要在DOM中使用的元素,那么为插件用户提供一些访问这些元素的方法是个好主意。有时这意味着给予某些元素ID或类。但请注意,您的插件不应该在内部依赖这些钩子:
执行不良
1
2
3
4
|
// Plugin code $( "" ).appendTo( "body" ); $( ".gallery-wrapper" ).append( "..." ); |
为了允许用户访问甚至操纵该信息,您可以将其存储在包含插件设置的变量中。以前的代码的更好的实现如下所示:
1
2
3
4
五
6
7
|
// Retain an internal reference: var wrapper = $( "" ) .attr( settings.wrapperAttrs ) .appendTo( settings.container ); // Easy to reference later... wrapper.append( "..." ); |
请注意,我们创建了一个引用包装器的引用,并且我们还调用该.attr()
方法来向元素添加任何指定的属性。所以在我们的设置中可能会像这样处理:
1
2
3
4
五
6
7
8
9
10
|
var defaults = { wrapperAttrs : { class: "gallery-wrapper" }, // ... rest of settings ... }; // We can use the extend method to merge options/settings as usual: // But with the added first parameter of TRUE to signify a DEEP COPY: var settings = $.extend( true, {}, defaults, options ); |
在$ .extend()方法现在将通过所有嵌套对象递归给我们设定值和通过选择两者的合并版本,给人传递的选项优先。
插件用户现在有权力指定该包装器元素的任何属性,因此如果它们需要任何CSS样式的钩子,那么他们可以很容易地添加一个类或更改ID的名称,而无需去挖掘插件源码。
可以使用相同的模型来让用户定义CSS样式:
1
2
3
4
五
6
7
8
9
10
|
var defaults = { wrapperCSS: {}, // ... rest of settings ... }; // Later on in the plugin where we define the wrapper: var wrapper = $( "" ) .attr( settings.wrapperAttrs ) .css( settings.wrapperCSS ) // ** Set CSS! .appendTo( settings.container ); |
您的插件可能有一个关联的样式表,开发人员可以添加CSS样式。即使在这种情况下,最好提供一些方便的方法来设置JavaScript中的样式,而无需使用选择器来获取元素。
链接提供回调功能
什么是回调? - 回调本质上是一个稍后调用的函数,通常由一个事件触发。它作为参数传递,通常是组件的发起调用,在这种情况下是一个jQuery插件。
如果您的插件由事件驱动,那么为每个事件提供回调功能可能是一个好主意。此外,您可以创建自己的自定义事件,然后为其提供回调。在这个gallery插件中添加一个“onImageShow”回调可能是有意义的。
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
var defaults = { // We define an empty anonymous function so that // we don‘t need to check its existence before calling it. onImageShow : function() {}, // ... rest of settings ... }; // Later on in the plugin: nextButton.on( "click", showNextImage ); function showNextImage() { // Returns reference to the next image node var image = getNextImage(); // Stuff to show the image here... // Here‘s the callback: settings.onImageShow.call( image ); } |
而不是通过传统方式(加括号)启动回调,我们在上下文中调用它将image
是对图像节点的引用。这意味着您可以通过this
回调中的关键字访问实际的图像节点:
1
2
3
4
五
6
7
|
$( "ul.imgs li" ).superGallery({ onImageShow: function() { $( this ).after( "" + $( this ).attr( "longdesc" ) + "" ); }, // ... other options ... }); |
同样,您可以添加一个“onImageHide”回调函数和其他许多回调函数。回调点是给插件用户一个简单的方法来添加额外的功能,而不需要在源代码中挖掘。
链接记住,这是一个妥协
您的插件无法在每种情况下工作。同样地,如果您提供的控制方法不是很少或很少,则不会非常有用。所以,请记住,这将是一个妥协。您必须始终考虑的三件事情是:
- 灵活性:您的插件可以处理多少情况?
- 大小:插件的大小是否对应于其功能级别?也许你使用一个非常基本的工具提示插件,如果它是20k的大小?- 可能不会!
- 性能:您的插件是否以任何方式大量处理选项?这是否影响速度?为最终用户带来的开销是否值得?