链接 提供对默认插件设置的公共访问权限
我们可以而且应该对上述代码进行的一项改进是公开默认插件设置。这很重要,因为它使用户能够使用最少的代码覆盖/自定义插件。而这是我们开始利用函数对象的地方。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
|
现在用户可以在其脚本中包含如下代码行
1
2
3
|
|
现在我们可以像这样调用插件方法,它将使用蓝色前景颜色
1
|
|
如你所见,我们允许用户编写一行代码来更改插件的默认前景颜色。而且用户仍然可以在需要时有选择地覆盖此新默认值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
|
链接 提供对辅助函数的公共访问权限(如适用)
此项与上一项齐头并进,并且是扩展插件(并允许其他人扩展插件)的一种有趣方式。例如,插件的实现可以定义一个名为“format”的函数,该函数格式化高亮文本。我们的插件现在可能如下所示,其中格式化方法的默认实现定义在 hilight 函数下方
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
|
我们本可以同样轻松地支持选项对象上的另一个属性,该属性允许提供回调函数来覆盖默认格式。这是支持插件自定义的另一种极佳方式。此处所示的技术更进一步,实际上公开了 format 函数,以便可以重新定义它。使用此技术,其他人可以发布他们自己的插件自定义覆盖——换句话说,这意味着其他人可以为你的插件编写插件。
考虑到我们在本文中构建的简单示例插件,您可能想知道这什么时候会派上用场。一个实际示例是 Cycle 插件。Cycle 插件是一个幻灯片插件,支持许多内置过渡效果——滚动、滑动、淡入淡出等。但现实情况下,无法定义一个人可能希望应用于幻灯片过渡的每种类型效果。这就是这种类型的可扩展性派上用场的地方。Cycle 插件公开了“transitions”对象,用户可以向其中添加自己的自定义过渡定义。它在插件中定义如下
1
2
3
4
5
|
|
此技术使其他人能够定义和发布过渡定义,这些定义可插入到 Cycle 插件中。
link 保持私有函数私有
公开插件的一部分以供覆盖的技术非常强大。但您需要仔细考虑公开实现的哪些部分。一旦公开,您需要记住,对调用参数或语义的任何更改都可能破坏向后兼容性。一般来说,如果您不确定是否公开特定函数,那么您可能不应该公开。
那么,我们如何定义更多函数,而不会使命名空间混乱且不会公开实现?这是闭包的任务。为了演示,我们将向我们的插件添加另一个名为“debug”的函数。debug 函数会将所选元素的数量记录到控制台。要创建闭包,我们将整个插件定义包装在一个函数中(如 jQuery 创作指南中所述)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
|
我们的“debug”方法无法从闭包外部访问,因此对我们的实现是私有的。
###Bob 和 Sue
假设 Bob 创建了一个很棒的新图库插件(称为“superGallery”),该插件获取图像列表并使其可导航。Bob 抛出了一些动画以使其更有趣。他试图使插件尽可能地可自定义,最终得到了类似这样的东西
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
|
您首先想到的可能是(好吧,也许不是首先想到的)这个插件必须有多大才能适应如此高的自定义级别。如果插件不是虚构的,那么它可能比必要的大很多。人们愿意花费的千字节数是有限的!
现在,我们的朋友 Bob 认为这一切都很好;事实上,他对插件及其自定义级别印象深刻。他相信所有选项都构成了一个更通用的解决方案,该解决方案可用于许多不同情况。
我们的另一位朋友 Sue 决定使用此新插件。她设置了所需的所有选项,现在面前有一个可行的解决方案。仅在使用插件五分钟后,她意识到如果每个图像的宽度以较慢的速度进行动画处理,那么图库看起来会更漂亮。她匆忙搜索 Bob 的文档,但没有找到 animateWidthDuration 选项!
link 您发现问题了吗?
这实际上与插件有多少选项无关;而是与它有哪些选项有关!
Bob 有点过头了。他提供的自定义级别虽然看起来很高,但实际上却很低,尤其是考虑到使用此插件时人们可能想要控制的所有可能的事情。Bob 犯了一个错误,即提供了许多非常具体的选项,这使得他的插件更难自定义!
link 更好的模型
因此很明显:Bob 需要一个新的自定义模型,该模型既不放弃控制也不抽象必要的细节。
Bob 如此热衷于这种高级简单性的原因是 jQuery 框架非常适合这种心态。提供 previousButtonTextColor 选项既好又简单,但让我们面对现实吧,绝大多数插件用户都希望获得更多控制!
以下是一些提示,可以帮助您为插件创建一组更好的可自定义选项
link 不要创建特定于插件的语法
使用您插件的开发人员不应学习新语言或术语才能完成工作。
Bob 认为他通过 delay 选项提供了最大的自定义(见上文)。他做到了这一点,通过他的插件,您可以指定四个不同的延迟,“相当短”、“非常短”、“相当长”或“非常长”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
|
这不仅限制了人们的控制级别,而且还占用了相当多的空间。仅定义延迟时间就需要十二行代码,是不是有点多?构建此选项的更好方法是让插件用户将时间(以毫秒为单位)指定为一个数字,以便无需对选项进行任何处理。
这里的关键是不要通过抽象来降低控制级别。您的抽象,无论是什么,都可以像您希望的那样简单,但请确保使用您插件的人仍然拥有非常需要的低级别控制!(低级别是指非抽象的。)
link 提供元素的完全控制
如果您的插件创建要在 DOM 中使用的元素,那么为插件用户提供一些访问这些元素的方法是一个好主意。有时这意味着为某些元素提供 ID 或类。但请注意,您的插件在内部不应依赖这些挂钩
糟糕的实现
1
2
3
4
|
|
为了允许用户访问甚至操作该信息,可以将它存储在包含插件设置的变量中。下面展示了之前代码更好的实现
1
2
3
4
5
6
7
|
|
请注意,我们已经创建了对注入包装器的引用,并且我们还调用了.attr()
方法来向元素添加任何指定属性。因此,在我们的设置中,它可能会这样处理
1
2
3
4
5
6
7
8
9
10
|
|
$.extend()方法现在将递归遍历所有嵌套对象,为我们提供默认值和传递选项的合并版本,使传递的选项优先。
插件用户现在有权指定该包装器元素的任何属性,因此,如果他们要求为任何 CSS 样式提供一个钩子,那么他们可以很容易地添加一个类或更改 ID 的名称,而无需在插件源中四处挖掘。
可以使用相同的模型来让用户定义 CSS 样式
1
2
3
4
5
6
7
8
9
10
|
|
你的插件可能有一个关联的样式表,开发人员可以在其中添加 CSS 样式。即使在这种情况下,提供一种在 JavaScript 中设置样式的便捷方式也是一个好主意,而无需使用选择器来获取元素。
link 提供回调功能
什么是回调? - 回调本质上是一个稍后调用的函数,通常由事件触发。它作为参数传递,通常传递给组件的初始调用,在本例中,是 jQuery 插件。
如果你的插件是由事件驱动的,那么为每个事件提供回调功能可能是一个好主意。此外,你可以创建自己的自定义事件,然后为这些事件提供回调。在这个画廊插件中,添加一个“onImageShow”回调可能是有意义的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
|
我们没有通过传统方式(添加括号)来启动回调,而是通过image
的上下文来调用它,这将是对图像节点的引用。这意味着你可以通过回调中的this
关键字访问实际的图像节点
1
2
3
4
5
6
7
|
|
同样,你可以添加一个“onImageHide”回调和许多其他回调。回调的目的是为插件用户提供一种简单的方法来添加附加功能,而无需在源代码中四处挖掘。
link 记住,这是一个妥协
你的插件不可能在所有情况下都工作。同样,如果你提供很少或没有控制方法,它也不会非常有用。因此,请记住,这总是一个妥协。你必须始终考虑的三件事是
- 灵活性:你的插件能够处理多少种情况?
- 大小:你的插件大小是否与其功能级别相符?即,如果一个非常基本的工具提示插件大小为 20k,你会使用它吗?——可能不会!
- 性能:你的插件是否以任何方式大量处理选项?这是否会影响速度?造成的开销是否值得最终用户使用?