锻造车间 - 编写 jQuery 插件

作者:Reuven M. Lerner

过去两个月,本专栏探讨了用于 JavaScript 编程的 jQuery 库。jQuery 是近年来涌现的几个流行的库之一(如 Prototype、YUI 和 Dojo),它使得以更令人满意和响应迅速的方式使用 JavaScript 成为可能,通过融入类似桌面的行为。

jQuery 受欢迎的部分原因是其庞大的插件库。几乎可以找到任何你能想到的功能的插件——从 GUI 小部件到导航辅助工具到文本转换。插件使得隔离和重用某些行为成为可能,从而实现 Ruby 世界中称为 DRY(不要重复自己)的目标。

正如我上个月展示的那样,使用插件通常非常容易。下载插件;安装随附的任何 CSS 和 JavaScript 文件,然后使用标准的 <script> 标签将 JavaScript 文件合并到您网站的一个或多个 HTML 页面中。最后,使用 jQuery 的事件处理函数,通常插入到 $(document).ready 中,将插件附加到一个或多个页面元素。

如果您使用 jQuery,并且发现自己一遍又一遍地重复相同的 JavaScript 模式,您可能需要考虑编写自己的插件。是否将该插件分发给 jQuery 社区的其他成员取决于许多因素,但通过将其制作为插件,您可以使您的所有应用程序都以类似的方式加载和使用该库。

Hubellubo Wuborld

jQuery 插件是 JavaScript 代码的打包机制。这意味着要创建您的插件,您首先必须有一些需要打包的 JavaScript 代码。

因此,作为本月的示例,我决定创建一个简单的 Ubbi Dubbi 翻译器。Ubbi Dubbi,正如你们中的一些人可能知道的那样,是儿童的“秘密”语言,在 1970 年代(我观看时)由美国公共电视台节目 Zoom 推广,然后在 1990 年代再次流行。Ubbi Dubbi 的规则很简单。每个元音(a、e、i、o 和 u)都以字母 ub 为前缀。所以,hello 变成 hubellubo。自学说 Ubbi Dubbi 并不难,而且听起来很滑稽。试试看!

无论如何,让我们首先创建一个基本的 JavaScript 程序,使用 jQuery,当鼠标光标悬停在文本上时,将文本转换为 Ubbi Dubbi。让我们从一个简单的 HTML 文件 ubbi.html(列表 1)开始。正如您所见,此文件中没有 JavaScript 代码。相反,我们将使用 jQuery 鼓励的“非侵入式”风格,将我们的 JavaScript 代码编写在一个单独的文件(ubbi.js,列表 2)中,然后我们通过 <script> 标签包含该文件。

列表 1. ubbi.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript" src="ubbi.js"></script>
    <link rel="stylesheet" type="text/css"
          media="screen" href="ubbi.css" />

    <title>Ubbi Dubbi</title>
  </head>
  <body>
    <h1>Ubbi Dubbi</h1>
    <p class="ubbi">This is in Ubbi Dubbi.</p>
    <p class="ubbi">
      Today, we will learn how to make cereal.
      First, pour the cereal into a bowl.
      Then pour milk onto the cereal.
      Finally, eat the cereal with a spoon. Delicious!
    </p>
  </body>
</html>

列表 2. ubbi.js

function ubbify(text) {
    return text.replace(/([aeiou])/gi, 'ub$1');
}

$(document).ready(function() {
    $(".ubbi").bind('mouseover',
                    function() {
                        var original_text = $(this).html();
                        $(this).attr({originalText: original_text});
                        $(this).html(ubbify(original_text));
                    });

    $(".ubbi").bind('mouseout',
                    function() {
                        $(this).html($(this).attr("originalText"));
                        $(this).attr({originalText: ""});
                    });

});

HTML 本身并不令人惊讶或兴奋。我们有两个文本段落,每个段落都分配了类 ubbi。在 JavaScript 文件中,我们使用 .ubbi 选择器为 mouseover 和 mouseout 事件设置处理程序。这就是奇迹真正发生的地方。当鼠标悬停在指定的段落上时,文本被转换为 Ubbi Dubbi。当鼠标移开时,文本恢复为其原始形式。

翻译取决于我们的 ubbify 函数,其定义如下

function ubbify(text) {
    return text.replace(/([aeiou])/gi, 'ub$1');
}

上面的 JavaScript 函数接受一个文本参数。它将任何元音替换为字符串 ub,后跟被替换的字母。诚然,这里有一个与以元音开头的大写单词相关的错误。修复该错误留给读者作为练习。

我们的 mouseover 处理程序定义如下

$(".ubbi").bind('mouseover',
                function() {
                    var original_text = $(this).html();
                    $(this).attr({originalText: original_text});
                    $(this).html(ubbify(original_text));
                });

这通过使用 jQuery 的 bind 函数来实现,当特定事件在 HTML 元素(或元素集合)上触发时,该函数会调用一个函数。因此,在这种特定情况下,我们告诉 JavaScript,每个类为 ubbi 的 HTML 元素都应该在鼠标光标悬停在其上时调用我们的函数。该函数本身抓取原始文本,将其放入名为 originalText 的属性中,然后用 ubbified 文本替换原始文本。

mouseout 处理程序类似,执行大致相反的操作,但没有 ubbification

$(".ubbi").bind('mouseout',
                function() {
                    $(this).html($(this).attr("originalText"));
                    $(this).attr({originalText: ""});
                });

为了增加一些活力和样式,我们还有 ubbi.css,它使用 .ubbi:hover 伪选择器在鼠标悬停在文本上时对其进行着色和斜体化(列表 3)。

列表 3. ubbi.css

.ubbi:hover {
  font-style: italic;
  border: 0.5px dashed #000;
  background-color: #cc9999;
}

CSS 和 JavaScript 的结合既有趣又有点令人兴奋。通常,文本看起来符合您的预期。但是,当您将鼠标移到一段文本上时,它会转换为 Ubbi Dubbi。Prubetty cubo-ubol,rubight?(相当酷,对吧?)

制作插件

这段 JavaScript 代码工作得很好。但是,可能普遍需要 Ubbi Dubbi 翻译器,当鼠标悬停在文本上时激活。如果有人可以简单地使文档中的每个段落都自动 Ubbify,那就太好了,通过

$(document).ready(function() {
                      $("p").ubbify();
                  });

为了做到这一点,让我们创建一个 jQuery 插件。插件在合并后,将向 jQuery 对象添加一个新函数。这意味着,我们的 ubbify 函数不再位于全局命名空间中,也不再从事件处理程序中调用,我们将在 jQuery 命名空间中定义一个函数,它将由也在该命名空间中定义的处理程序调用。

为了实现这一点,我们需要稍微重组一下。首先,我们需要重命名我们的 JavaScript 文件,因为每个插件都需要采用 jquery.PLUGIN.js 格式。在这种情况下,我将其命名为 jquery.ubbi.js。

接下来,我们需要定义我们的 ubbify 函数,以便全局 jQuery 对象能够识别它。为此,我们在 jQuery 命名空间内定义 ubbify

$.fn.ubbify = function () {
                  // implementation goes here
              }

等一下——我们正在定义的 $.fn 是什么?事实证明,如果我们想为 jQuery 对象定义一个全局方法,通常别名为 $,我们必须将该函数分配给 $.fn 对象。

但是,再等一下——可以重新定义 $,使其不再是 $ 函数的别名。这使得 jQuery 可以与 Prototype 等 JavaScript 库很好地配合使用,Prototype 也使用 $,但方式非常不同。因此,许多 jQuery 插件教程告诉您不要使用 $,而是使用完整的 jQuery 对象,如下所示

jQuery.fn.ubbify = function () {
                       // implementation goes here
                   }

另一种解决方案是将整个函数定义包装在闭包(即具有状态的函数)中,将闭包作为具有变量绑定的环境提供给 jQuery 对象

($.fn.ubbify = function () {
                   // implementation goes here
               });

现在我们已经解决了这个问题,我们可以在其新的插件主目录中定义我们的函数。列表 4 包含 jquery.ubbi.js,这是一个 jQuery 插件,它执行我们之前所做的所有操作,但在插件的上下文中。

列表 4. jquery.ubbi.js

(function($) {
    $.fn.ubbi = function(options) {
        // Private function
        function ubbify(text) {
            return text.replace(/([aeiou])/gi, 'ub$1');
        }

        // Return the results of iterating over our inputs
        return this.each(
            function() {
                $(this).bind(
                    'mouseover',
                    function() {
                        var original_text = $(this).html();
                        $(this).attr({originalText: original_text});
                        $(this).html(ubbify(original_text));
                    });

                $(this).bind(
                    'mouseout',
                    function() {
                        $(this).html(
                        $(this).attr("originalText"));
                        $(this).attr({originalText: ""});
                    });
            });
    };

})(jQuery);

关于 jQuery 最有趣的事情之一是,由于 CSS 选择器的存在,它可以接受任意数量的参数。可以为单个段落调用一个函数,通过 DOM ID 标识。或者,它可以在许多标签上调用,或者在具有特定类的标签上调用。我们的函数需要处理所有或任何这些情况,并且当它完成时,我们的函数必须返回 jQuery 对象,以便可以将其使用“链接”到另一组指令。

我们通过迭代每个参数并返回结果来做到这一点,如下所示

return this.each(
    function() {
        ...
    });

jQuery 将 .each 定义为迭代器,它对调用它的对象的每个元素进行操作。在这种情况下,我们获取每个提交的元素并将它们传递给一个函数。当然,该函数分配事件处理程序 mouseover 和 mouseout。请注意,这些函数现在是如何在 $(this) 上调用的,$(this) 是当前元素的 jQuery 版本。

最后,我们的 ubbify 函数在 $.fn.ubbi 定义中私有定义。我们的 ubbify 函数可供 $.fn.ubbi 的定义中的任何和所有用户使用,诚然,目前函数数量非常少。

在我们的插件就位后,我们所要做的就是告诉我们的 HTML 文件加载插件并以正确的方式调用它

<script type="text/javascript" src="jquery.ubbi.js"></script>
<script type="text/javascript">
  $(document).ready(function() {
                        $(".ubbi").ubbi();
                    });
</script>

请注意,必须在加载任何插件之前加载 jquery.js。我们可以使用以下方法将我们的 ubbi 插件应用于页面上的所有段落

$("p").ubbi();

有了我们的 Ubbi 插件(plubugubin?),现在为人们提供 Ubbi Dubbi 翻译变得容易得多。感谢 jQuery 的插件机制,我们可以分发我们的插件供其他人使用,而无需阅读或理解代码。我们修改后的简单 HTML 文件如列表 5 所示。

列表 5. ubbi2.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript" src="jquery.ubbi.js"></script>

    <script type="text/javascript">
      $(document).ready(function() {
                            $(".ubbi").ubbi();
                        });
    </script>

    <link rel="stylesheet" type="text/css"
          media="screen" href="ubbi.css" />

   <title>Ubbi Dubbi</title>
  </head>
  <body>
    <h1>Ubbi Dubbi</h1>
    <p class="ubbi">This is not in Ubbi Dubbi.</p>
    <p class="ubbi">
      Today, we will learn how to make cereal.
      First, pour the cereal into a bowl.
      Then pour milk onto the cereal.
      Finally, eat the cereal with a spoon. Delicious!
    </p>
  </body>
</html>

结论

jQuery 是一个令人惊叹的 JavaScript 库,但其特别令人印象深刻的功能之一是对插件的支持。既然您已经了解了编写插件是多么容易,请尝试思考如何通过为他人发布一个或多个插件来为社区提供价值。

资源

关于 JavaScript 和 jQuery 有很多资源,包括印刷版和在线资源。

在 Packt Press 出版的书籍中,我喜欢 Jonathan Chaffer 和 Karl Sweebber 编写的 Learning jQuery,这本书非常适合已经有其他语言经验(甚至可能是 JavaScript)的 Web 开发人员。它回顾了 JavaScript 程序员可以使用 jQuery 完成的许多不同类型的功能。

David Flanagan 的 JavaScript: The Definitive Guide 仍然是一本优秀的资源,尽管我承认拥有 jQuery 已经大大减少了我需要了解的基础 JavaScript 知识。

同样,有很多博客文章可能会有所帮助,包括:www.learningjquery.com/2007/10/a-plugin-development-patterntkramar.blogspot.com/2008/02/improve-your-jquery-fu-write-plugins.htmlwww.bennadel.com/blog/800-My-First-jQuery-Plugin.htm

Reuven M. Lerner,一位长期的 Web/数据库开发人员和顾问,是西北大学学习科学专业的博士候选人,研究在线学习社区。最近,他在芝加哥地区生活四年后,(与妻子和三个孩子)返回以色列莫迪因的家。

加载 Disqus 评论