使用 jQuery,第 3 部分: 用 jQuery 和 Ajax 构建富 Internet 应用程序

效果和 Ajax

jQuery 是一种 JavaScript 库,它是开发人员简化动态富 Internet 应用程序的创建过程的最佳选择。随着基于浏览器的应用程序不断代替桌面应用程序,这些库的使用将越来越广泛。您将通过本系列文章中了解 jQuery,并学习如何在 Web 应用程序项目中实现 jQuery。

Michael Abernethy, 产品开发经理, Optimal Auctions

Mike Abernethy在 10 的年技术生涯中,Michael Abernethy 与各种不同的技术和客户机打交道。他目前是一家拍卖软件公司 Optimal Auctions 的产品开发经理。他现在专注于富 Internet 应用程序,试图同时实现应用程序的复杂性和简单性。他在空闲时常常带上自己最喜欢的书去墨西哥湾海滩度假。



2008 年 12 月 12 日

简介

最近这几个月以来,JQuery 受欢迎的指数迅速攀升,现已成为 Web 开发人员首选的 JavaScript 库。与此同时,人们对富 Internet 应用程序(Rich Internet Application,RIA)的应用和需求也在迅速增长,并期待用基于浏览器的应用程序代替桌面应用程序。无论是电子表格,还是薪水册和电子邮件应用程序,现在都在浏览器中再现了类似于桌面的体验。随着这些应用程序数量的增多和功能的日益复杂,JavaScript 库将会变得越来越重要,因为它是构建这些应用程序的坚实基础。JQuery 无疑成为了开发人员最佳选择。本系列文章深入探索了 jQuery,并提供了坚实的基础。开发人员借助这个基础就可以快速轻松地构建自己的 RIA。

在本系列 之前的一篇文章 中,您了解了用来构建 RIA 以及为页面添加交互性的三个基本组件。第一个模块是 Event 模块,借助此模块,能捕获用户对页面的任意交互并以编程的方式进行响应。比如,您可以向按钮点击、鼠标移动等事件附加代码。下一个模块是 Attributes 模块,它解释了如何在页面元素上获得/设置值,以及如何将其作为带有变量的数据对象。这些值包含了决定为用户提供何种响应的大部分信息。最后,您还看到了 如何进行 CSS 处理,以及如何在不重新加载页面的情况下更改页面上任意元素的布局、颜色、字体等。了解这三个模块之后,就等于掌握了交互 Web 页面的三个基本元素 — 获取用户交互(Event)、收集信息(Attribute)以及在事件和信息基础上提供反馈(CSS)。

在本文中,将对交互 Web 页面的这三个基本元素进行更进一步的探究,提供当今高级 Web 应用程序必备的 “酷” 效果和特征。这些附加的模块对提供 RIA 而言并不是至关重要的,但这些效果和特征会给用户留下深刻印象,并且还会极大地扩展 RIA 的可用范围和特性。您将看到的第一个模块是 Effects 模块,它包含很多特性,比如隐藏元素、随处移动元素、淡入淡出元素等。换言之,这些都是让 Web 页酷起来的 “亮点”。最后一个要讨论的模块是 Asynchronous JavaScript + XML (Ajax) 模块。大多数人都将该模块等同为 RIA。Ajax 让 Web 应用程序无需重载页面就能与服务器进行交互、向服务器传递信息并从中获取信息(与 Web 上的一些意见相反,Ajax 单纯是一个很酷的 JavaScript 动画工具)。您将发现 jQuery 提供了极其简单易用的 Ajax 工具。实际上,jQuery 使 Ajax 的使用与调用其他 JavaScript 方法一样简单。

本文中的示例应用程序是个总结,展示了 Effects 和 Ajax 模块如何融入到这个示例 Web 邮件应用程序中。我将向这个示例程序添加一些效果使其更加漂亮,而且更重要的一点是,我将添加一些 Ajax 代码,以便无需重载页面邮件应用程序就能显示信息。

Effects 模块

从其名字往往容易得出这样的结论,Effects 模块只包含一些动画和效果,而这些动画和效果往往是一些 “正规” 的 Web 页面所竭力避免的。但实际情况并非如此。几乎所有的应用程序都会遇到这样的情况,即某个页面元素需要隐藏或其视图应该根据另一个页面元素的状态进行切换。这类更改对于一个 RIA 而言非常重要,因为它们让您能够加载某个页面的所有页面元素,然后通过隐藏/显示特定的元素只显示所需的信息。重载页面的方式并不可取。比如一个具有两个选项的组合框,一个选项是隐藏 div,一个选项是显示此 div。很显然,与更改组合框并重载页面隐藏/显示 div 相比,用客户端代码隐藏/显示此 div 更简单和高效。而仅隐藏/显示还是要让它淡入/淡出,则完全取决于您。

如上所述,最基本的效果函数是 show()hide() 函数。这非常直观;它们可分别用来显示和隐藏页面上的某个元素。

清单 1. 隐藏和显示函数
// shows every <p> on the page
$("p").show();

// hides every <p> on the page
$("p").hide();

// hides every other <p> on the page
$("p:odd").hide();

除了这些基本操作,利用 show()hide() 这两个函数,还能更多地控制页面元素如何显示和隐藏。相关文档将 hide() 描述为 “优美” 的显示/隐藏,对于 show(),就是综合淡入和滑出的效果。

在开始深入探讨一些例子之前,不妨回过头来看看传递给这些效果函数的参数。每个函数(除了通用的 show()hide() 函数之外)都允许在效果完成时传入要调用的速度和函数。速度用来控制效果出现的快慢。这个参数可以是一个 "slow""fast""normal" 字符串。此外,如果需要精确控制动画时间,那就需要用参数指定毫秒数。Effects 函数的第二个参数本身就是一个函数,此函数在效果完成后调用。如果想要将几个效果组合成一个较大规模的效果,这一点将非常重要,因为利用它,能够可靠地控制一个效果何时完成,下一个效果何时开始。

清单 2. 复合效果
// the img with an ID of "picture" should start hidden
// when the "showPicture" button is pressed, show the img with an ID of "picture"
// and animate it, so it appears quickly in a fade In and slide out, and when
// it's done being shown, show the caption of the picture, which is
// always in the span right after the <img> tag

<input type="button" id="showPicture">

<img src="/pic.jpg" id="picture"><span>This is the picture's caption</span>

// jQuery code inside the document.ready() function

$("#picture").hide().next().hide();
$("#showPicture").click(function(){
   $("#picture").show("fast", function(){
       $("#picture").next().show();
   });
});

// notice how it took more text to describe what you want to happen than it took
// to actually code it!

Effects 模块还有其他一些函数,它们与 show()hide() 非常类似,并且最终所实现的功能也基本相同;只不过实现的方式不同。slideDown()slideUp() 函数分别用来显示和隐藏一个页面元素。不过,这是通过将该元素滑下或滑上的动画效果实现的(从其名称中不难看出这一点)。与我刚刚提到的增强了的 hide()show() 函数类似,您也可以控制滑动的速度以及在效果完成时要调用的函数。此外,要显示/隐藏页面元素还有另一种选择,即 fadeIn()fadeOut() 函数,正如其名字所示,这两个函数用来淡入页面元素直至该元素透明,然后使该元素消失。它们允许在效果完成时定制速度和要调用的函数。

有一个很有趣的函数,它可部分隐藏和显示页面元素,此函数是 fadeTo(),它能让页面元素部分透明。我认为此函数对 RIA 很重要,因为透明性是突出页面上某个元素的一种很好的方式,并可用来显示页面的禁用区域。例如,页面上有几个选项卡,可以让所有未被选中的选项卡呈现一些透明性来突出其未被选中。或者,在一个页面表单上,可以让所有没有焦点的元素呈现一些透明性以向用户突出哪个 Form 元素当前具有焦点。此外,透明性本身就很酷。在进行设计时,不妨遵循这样一条通用的箴言 “如果苹果公司这么设计,效果一定很酷”。

清单 3. 使用 fadeTo() 增添很酷的效果
// make all the Form elements on the page show transparency at 60%, except
// the one that currently has focus, which will not have any transparancy.  
// This is Apple cool!

$(":input").fadeTo("fast", .60);
$(":input").focus(function(){
    $(this).fadeTo("fast", 1);
});
$(":input").blur(function(){
    $(this).fadeTo("fast, .60);
    });

我想要强调的 Effects 模块内的最后一个函数是最酷也是最容易出错的。它是一种定制动画的方法,允许您定义动画的所有参数,而剩下的工作则由 jQuery 负责处理。您负责提供一个参数数组以及这些参数的最终值,jQuery 负责决定这些参数的当前值。而且,动画的速度也可指定,这能使页面元素动画的运行比较平稳,直至达到您所提供的最终值。清单 4 给出了此定制动画方法的一个例子。显然,该函数提供很多可能性,如果您想要自己定制动画,不妨多进行练习。

清单 4. 定制动画的方法
// when the button is clicked, make the div with an ID of "movingDiv"
// have the custom animation provided.
$("#myButton").click(function(){
   $("#movingDiv").animate({
      // will increase the width, opacity, and fontSize of "movingDiv"
      // and do it in 5 seconds
      width: 700;
      opacity: 0.5;
      fontSize: "18px";
   }, 5000);
   });

Ajax

当前,与 Web 页面有关的最流行的一句话就是 “它用到 Ajax 了吗”,但是,是不是每个人都能真正理解 Ajax 的含义呢?在 Google 上搜索 “Ajax” 将会出现数百万个搜索结果(与大多数搜索一样),但是,这么多结果似乎表明对术语 Ajax 真正含义的理解还存在一些含糊不清之处。Ajax 并不是 某些页面上出现的一些很酷的动画,也不是弹出窗口下一个很酷的阴影效果。Ajax 很酷,但并不意味着 Web 页上的任何一个令人耳目一新的东西都是 Ajax 的成果。Ajax 的核心是在不重载页面的情况下客户端 Web 页面能与服务器来回传递信息。所以,虽然 Ajax 并不能提供页面上的绚丽效果,但利用 Ajax 却能使 Web 应用程序真实模仿桌面应用程序。所以,围绕 Ajax 沸沸扬扬的现象是有其根源的 —— Ajax 的广泛应用直接导致了目前 RIA 的迅速发展。

jQuery 则让使用 Ajax 变得异常简单!我并不是夸大其词。在没有 JavaScript 库的情况下使用过 Ajax 的人都知道,他们必须处理 XMLHttpRequests、处理 XMLHttpRequest 的 Microsoft® 和 Firefox 版本间的差异、必须解析全部返回代码等,而 jQuery 则让使用 Ajax 简单到进行一次函数调用即可。这是真的!原先需要 100 行代码才能完成的功能现在只需 3 或 4 行代码就可以了。这节省了多少时间啊!就我个人而言,获悉 jQuery 之前,若想添加 Ajax 函数往往需要大量工作。现在,有了 jQuery,这变得极其简单,并能让我的应用程序充分利用 Ajax 提供的全部益处。如果 Ajax 的使用能简单到一个常规的函数调用,那为什么不使用它呢?

现在来看看您最有可能在自己的 Ajax 需求中用到的两个函数:post()get() 方法。这些函数的运作与其他的 jQuery 函数没有太大差别,它们均允许指定要调用的 URL 以及要传递的参数,并指定 Ajax 方法返回时的函数。在这种意义上,这两个方法设置的方式使得在 jQuery 调用 Ajax 方法与在 jQuery 调用其他方法基本相同。参见清单 5。

清单 5. Post 和 get Ajax 方法
// this code would be in a php file named myTest.php
// why did I switch to PHP for the Ajax examples?  Java/JSP gets tough because
// you need to show the code in the Servlet, which isn't necessary with PHP.  The
// functions work equally well in both PHP and Java/JSP though.
<?php
     echo "This is my return String";
?>

// here's how simple the Ajax calls are in jQuery
// This is a post function
$.post("myTest.php", {}, function(data){
   $("p").text(data);
});

$.get("myTest.php", {}, function(data){
   $("p").text(data);
   });

正如这两个示例所示,这些函数与其他 jQuery 函数相同,因此比不带 JavaScript 库的情况更容易使用。有几个参数可用来扩展 Ajax 调用的函数。第一个参数很显然是要调用的 URL。这可以是 PHP 文件、一个 JSP 文件或 Servlet — 通常可以是处理此请求的任何东西。它甚至可以不响应此请求(正如您在以后的示例应用程序中看到的一样)。第二个参数是可选的,用来传递 post/get 的数据。一般采用数组格式。通常,需要传递在 Form 元素中包含的信息以及来自页面的 userID 信息等。基于服务器文件的所有东西都要处理此请求。第三个参数也是可选的,是 Ajax 函数成功返回时所要执行的函数。该函数一般包含用来处理由服务器传递回的信息结果的代码。清单 6 给出了这三个参数的一些例子,我随后还会介绍第四个参数。

清单 6. 用可选参数进行 post
// place a username and password input field on the page
<input type=text id="username">
<input type=password id="pass">

// call a server-based PHP file that will process the information passed to it
$.post("myFormProcessor.php", {username: $("#username").val(), 
                               password: $("#pass").val()});

// conversely, this PHP file could also return information to the function, from which
// you could process the results
$.post("myFormProcessor.php", {username: $("#username").val(), 
                               password: $("#pass").val()},
       function(data){
           // the data variable contains the text returned from the server, you don't
           // have to set anything up ahead of time, jQuery will do it all for you
           if (data != "ERROR")
              $("#responseDiv").text(data);
       }
       );

不难看出,在 jQuery 内处理 Ajax 非常直观和容易。不过,如果处理来自服务器的比文本字符串复杂的信息时,这些函数可以变得很复杂。在较多涉及 Ajax 调用的一些更为复杂的 Web 页面内,返回的数据结果通常都是 XML 格式的。返回的数据也可以是 JSON 对象格式的(JSON 是用来定义 JavaScript 对象的一种协议)。jQuery 还允许 get/post 方法有可选的第四个参数,以便提前就能指定由服务器返回值的类型。可以针对 XML 字符串传递 "xml" 字符串、针对 HTML 字符串(或纯文本)传递 "html"、针对 JavaScript 代码传递 "script"、针对 JSON 传递 "json"。所以,例如通过将返回对象指定为 "json" 类型,jQuery 将能自动将来自服务器的响应字符串转换成 JSON 对象,使您能够立即引用它。

清单 7. 指定 Ajax 内的返回类型
// specify the return object to be a type JSON object, and process the
// return object as a JSON object, referencing fields in it without
// casting it to any object or evaluating it

$.post("myFormProcessor.php", {username: $("#username").val(), 
                               password: $("#pass").val()},
       function(data){
          // jQuery has already converted the data response into a JSON object, so 
          // you can immediately reference its fields, providing cleaner-looking code
          // and allowing future changes, and in my opinion, making it easier to work
          // with than XML responses
          $("#username").text(data.username);
          $("#address").text(data.address);
          $("#phone").text(data.phone);
       }, 
       "json"  // here you specify that the return type is JSON
       );

我想花些时间讲述的另一个 Ajax 函数是 load(),它允许用户加载一个特定的页面并获取 HTML 作为结果。从这样的描述看起来,它并不那么吸引人。事实上,与在启动时解析 Web 页一样,您还需要解析使用 jQuery 代码返回的信息。这是什么意思呢?简单来说,如果能加载任何 Web 页面,继而又能用 jQuery 对之进行解析,也就实现了一个非常高效且易于编程的页面 scraper,借助这个 scraper,可以从所有页面搜集各类信息。让我们详细看看。

清单 8. load() 函数的示例应用程序
// create a very primitive stock price quote by calling Yahoo's stock quote, and then
// scraping the information from their pages.
// in this case, look up IBM's stock price, and place it in the text field with an ID of
// "stockPrice"
// the span with the ID of "yfs_l90_ibm" contains the stock price
$("#stockPrice").load("http://finance.yahoo.com/q?s=ibm #yfs_l90_ibm").text();

接下来我要介绍的 Ajax 模块的最后两个函数是两个真正的实用函数,它们非常有助于 Ajax 的使用。正如我已经多次指出的,客户机和服务器间的很多交互都会涉及到表单以及其中所包含的元素。由于这类通信很常见,所以在 jQuery 内已经有两个实用函数可用来协助构造传递给服务器的参数,参数可以是 HTTP 查询字符串的格式也可以是 JSON 字符串格式。可以使用这两个实用函数来为您的 Ajax 需求提供帮助。这两个函数的使用很方便,因为这二者均能封装整个表单,而不管在开发期间有多少元素被添加/删除/更改。清单 9 给出了这样一个例子。

清单 9. serialize()serializeArray() 函数
// the serialize function will look at every Form element inside the specified element
// and automatically construct an HTTP String that contains all the information
// of the elements, in the form of <element name>=<element value>&
// for example, "firstname=Michael&lastname=Abernethy"
// this can then be attached to the URL to pass the information via an Ajax call
$.post("myFormProcessor.php?" + $("#myForm").serialize());

// further, a similar thing could be done with the serializeArray function
// which will convert a Form into its JSON equivalent
$.post("myFormProcessor.php", {json: $("#myForm").serializeArray()});

综合学到的知识

要将本系列的所有课程综合起来,需要用到在前两个课程中都谈及的这个示例 Web 邮件应用程序。我将添加从客户端到服务器端的多个 Ajax 调用以收集信息。我还将使用 Ajax 来获得您读取消息时的消息信息,并利用 Ajax 方法来删除消息。之后,我会将一些效果融入其中以便当用户删除消息时,这些消息会立即从屏幕中删除,即便用户并没有重新加载此页面,而且实际的删除也是通过 Ajax 调用异步发生的。在本文结束之际,您将能再次感受到在 Web 应用程序中使用 Ajax 调用是多么容易,并了解到如何利用这些调用来实真实模仿桌面应用程序,以及如何利用 Effects 来增强应用程序的可用性。

清单 10. 示例 Web 应用程序 - 删除消息
// First, let's look at how you handle deleting a message.

// The first step is to create a button that will actually delete messages
<input type=button id="delete" value="Delete">

// next, you'll add a checkbox in each row of the table, so that users can select
// which messages they want to delete.  You'll use these checkboxes later, and
// the information contained in them is equally important (that's called
// foreshadowing!)
// Notice how the value of each checkbox is the message.id!

<tr class="messageRow" id="<%=message.id %>">
<input type=checkbox name="delId" value="<%=message.id%>" class=selectable>

// Now that the HTML is complete, look at the jQuery code to execute these deletes

// First, attach an event to the delete button, so when it's pressed, it will
// start deleting the checked messages

$("#delete").click(function() {
   deleteMessages();
});

// Finally, let's define the deleteMessage() function, because that contains the meat of
// today's lessons.
// Because this is the culmination of every lesson, let's look at everything I did to
// get this working!
// Note 1 - I loop through each of the checkboxes that are checked by passing in a very
// specific search parameter, to find only the members of the "selectable" class that
// are checked.
// Note 2 - because the value of the checkbox is the same as the ID of the table row in
// which it is contained, you can use the Effects module to hide the entire table row,
// by passing in the value of the checkbox, and getting the table row back, and then
// hiding it.
// Note 3 - I make an Ajax call to actually delete the message from the DB.  I have
// to pass the messageID to the server so that it knows which one to delete.  That
// information is contained in the checkboxes value, which I pass with the Ajax call.
// Because I don't really care if it's successful or not, I ignore any reply from
// the server.

function deleteMessages()
{
    $(".selectable:checked").each(function() {
        $("#"+$(this).val()).remove();
        $.post("<%=HtmlServlet.DELETE_MESSAGES%>.do", {delId: $(this).val()});
    });
    }

在第 2 个示例中,看一看如何读消息,这展示了如何在 jQuery 中使用 Ajax:

清单 11. 示例 Web 应用程序 - 读取消息
// You've seen most of this code previously in the example from last article, so let's
// focus on the Ajax portion of the code.
// Note 1 - I make an Ajax call with all 4 arguments defined.  I have to pass two
// variables to the server in order to read the message.  The first is the message
// ID number, because I need to know which message I want to read.  The second is
// the current view...for reasons I can't recall (not important really).
// Note 2 - The fourth argument into the Ajax function is "json", indicating that
// I expect a JSON object back from the Ajax call.  jQuery will automatically
// convert the response String into a JSON object.
// Note 3 - Notice that I handle the JSON object directly, without using an
// eval() function, because jQuery has already created the object.  I can
// reference its fields directly.
$(".messageRow").dblclick(function() {
    if ($(this).hasClass("mail_unread"))
    {
        $(this).removeClass("mail_unread");
    }
    $.post("<%=HtmlServlet.READ_MESSAGE%>.do", {messageId: $(this).attr("id"),
                                                     view: "<%=view %>"}, 
      function(data){
        if (data != "ERROR")
        {
             // using JSON objects
             $("#subject").val(data.subject);
             $("#message").val(data.message);
             $("#from").val(data.from);
         }
      }, "json");
    $.blockUI(readMess, {width:'540px', height:'300px'});
    });

结束语

随着应用程序不断从桌面向浏览器转移,像 jQuery 这样的 JavaScript 库的将越来越重要。应用程序越来越复杂,这就使跨浏览器的 jQuery 成为所有 Web 应用项目的必要工具。由于易于使用和功能完备,jQuery 逐渐从其他 JavaScript 库中脱颖而出,成为很多开发人员的最佳选择。

通过这个 jQuery 系列的第三篇文章,您接触到了另外两个模块,利用它们能为应用程序真正添加丰富性,并进一步模糊桌面应用程序和 Web 应用程序间界限。本课程中功能最强大的一个模块是 Ajax 模块,该模块能极大地简化 Ajax 的使用,使用它与进行其他 jQuery 方法调用一样简单直观。您还通过几个例子进一步领略了 Ajax 的强大功能并知道了 Ajax 是个很酷的工具,可在不重载页面和延迟的情况下加快应用程序的响应速度。此外,您了解了 Effects 包。并且知道,如果正确使用动画和隐藏/显示页面元素,将能大大增强 UI 设计。不仅如此,若能有效地综合使用,Ajax 和 Effects 还能极大地增加 Web 站点的动态性。

最后,您再次重温了这个示例 Web 应用程序,并体会了增加了 Ajax 模块后,您将能在无需重载页面的情况下读取和删除消息。然后您还看到了如何在 Web 应用程序中删除消息,并且通过综合 Ajax 和 Effects,还能从用户页面和 DB 删除消息,而这一切均无需重载此页面。对于用户而言,消息的删除是个透明的过程,而且您能通过编程实现此目的。

至此,与 JQuery 发布版一并提供的核心库相关的系列 JQuery 文章就结束了。这三篇文章为您一一展示了 jQuery 所包含的每个模块,让您看到了使用 jQuery 是多么容易和直观。此外,您还应该知道不管您所面对的是哪种 Web 应用程序,jQuery 应该都可以用来将其转变成任何类型的 RIA,因为 jQuery 是所有 JavaScript 需求的坚实基础。通过本系列文章对 jQuery 的介绍,您应该有信心在自己的代码中使用 jQuery。本系列的 第一篇文章 向您展示了 jQuery 是如何工作的,以及如何用它来搜索页面元素、循环遍历这些元素并像 Array 对象那样访问这些元素。本系列的 第二篇文章 向您介绍了对提供丰富性至关重要的三个模块。最后的这篇文章则给出了生成一个完整、复杂的 Web 应用程序所需的最后几个要素。


下载

描述名字大小
包含示例应用程序的 Zip 文件jquery.zip69KB

参考资料

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development
ArticleID=358366
ArticleTitle=使用 jQuery,第 3 部分: 用 jQuery 和 Ajax 构建富 Internet 应用程序
publish-date=12122008