跳转到内容

XML - 数据交换管理/AJAX

来自 Wikibooks,开放世界中的开放书籍



上一章 下一章
XUL Web 服务



AJAX 如今是 WEB 2.0 时代最常用的词语之一。虽然它历史的起源并不完全清楚(类似的操纵网页部分的逻辑早在 AJAX 术语出现之前就被认为是 DHTML,而且令人惊讶的是,它甚至使用了一些 DOM 类型),但它现在是现代网页设计师使用的最重要技术之一。
但 AJAX 到底是什么意思呢? - 简而言之,AJAX 代表 Asynchronous JavaScript and XML(异步 JavaScript 和 XML)。它描述了一种在客户端(通常是 Web 浏览器)和服务器之间进行异步数据传输(这里:封装在 XML 中的数据)的概念,只需要交换/更改网页的一部分,而无需完全重新加载页面。这意味着浏览器将在后台发出 XMLHttpRequest,并且只接收页面的一部分 - 通常与一个或多个包含 uid 的 HTML 标签相关联。

以下是 Ajax 编程模式的主要组成部分。

  • JavaScript - Web 上最流行的脚本语言,所有主要浏览器都支持。Ajax 应用程序是用 JavaScript 构建的。
  • 文档对象模型 (DOM) - 将网页结构定义为一组可编程对象。在 Ajax 编程中,DOM 允许我们重新绘制页面的一部分。
  • 层叠样式表 (CSS) - 提供一种定义网页上元素视觉外观的方法。
  • XMLHttpRequest - 允许客户端脚本执行 HTTP 请求,有效地消除了 Ajax 应用程序中的完全页面刷新或回发。
  • XML - 它有时用作在服务器和客户端之间传输数据的格式,但其他基于文本的格式也同样适用。

Ajax 提供了许多优势。以下列出了一些最重要的优势。

  • 带宽需求降低:由于在请求附加信息时无需完全重新加载页面,因此可以最大限度地减少数据传输。通过在浏览器中本地生成 HTML,带宽需求也降低了(注意:然而,由于我们有 JavaScript 嵌入带来的额外开销,因此只有当从同一站点进行多个或两个以上的页面请求时,这种情况才成立)。
  • 无需浏览器插件:Ajax 可以在支持 JavaScript 的所有浏览器中运行。不需要额外的插件。与 Shockwave 或 Flash 等技术相比,这是一个优势(注意:然而,在某些情况下,某些浏览器可能会表现不同;尤其是 IE 6 之前的版本以奇特的行为而闻名)。
  • 数据和格式分离:这使得 Web 应用程序更高效。程序员可以将通过 Web 传递信息的方法和格式分离。因此,他们可以使用他们熟悉的语言(注意:这是由于 CSS 而不是 AJAX)。
  • 网站更友好:由于数据传输量减少,用户操作的响应速度更快。此外,使用 Ajax 构建的界面可能更友好(注意:然而,没有回退到普通 HTML 请求响应循环的 AJAX 以其对无障碍 Web 设计构成巨大障碍而闻名)。

经典请求响应与 AJAX 循环

[edit | edit source]

如您在图像中所见,AJAX 循环在客户端嵌入了一个额外的 JavaScript 库。因此,JS 库用于与服务器通信(如果使用 AJAX),以及操作它嵌入的 HTML 页面。对于一个小例子,我们现在将看看所谓的自动完成(我们将在这里看看基本处理,并跳过详细的 JS-DOM 操作)。另一方面,传统方法始终需要一个完整的请求响应循环,将整个页面从服务器发送到浏览器。

一个简单的例子:自动完成

[edit | edit source]

此示例展示了一个来自 wicket 示例的简单自动完成文本字段(wicket 是 ASF 下的组件化 Java Web 框架 - http://wicket.apache.org/)。该示例在线 实时演示,因此您不仅可以遵循代码,还可以实时查看它的运行情况。


自动完成文本字段背后的理念是在用户填写字段时提供有用的可能性,以此来帮助用户。想象一下,您在 amazon.com 上寻找产品“foo”,您将其填写到搜索栏中,只是为了发现它在提交后不存在 - 使用自动完成感知的字段,您会在输入一些字母后就已知晓。为了有一个简单的例子,我们现在将看看一个单一的字段,您可以在其中输入国家/地区的名称,例如“England”、“Germany”或“Austria”。

它背后的 HTML 相当简单(必要的 JavaScript 会由 wicket 自动提供;类似于 prototype 等纯 JS 库所做的;当然,您可以提供自己的实现,即使这样做没有太大意义)。

... header containing CSS + HTML-head left out...
The textfield below will autocomplete country names. It utilizes AutoCompleteTextField in wicket-extensions.<br/><br/>

        <form wicket:id="form">
            Country: <input type="text" wicket:id="ac" size="50"/>
        </form>
...footer left out...

因此,我们目前只得到一个简单的表单,其中包含一个普通的 <input />。 “wicket:id”仅用于将其绑定到 Java 代码,对 AJAX 没有任何影响(实际上,在生产模式下,它会被剥离)。

Java 代码也不复杂

public class AutoCompletePage extends BasePage
{
    /**
     * Constructor of the AutoCompletePage
     */
    public AutoCompletePage()
    {
        Form form = new Form("form");
        add(form);

        final AutoCompleteTextField field = new AutoCompleteTextField("ac", new Model(""))
        {
            protected Iterator getChoices(String input)
            {
                if (Strings.isEmpty(input))
                {
                    return Collections.EMPTY_LIST.iterator();
                }

                List choices = new ArrayList(10);

                Locale[] locales = Locale.getAvailableLocales();

                for (int i = 0; i < locales.length; i++)
                {
                    final Locale locale = locales[i];
                    final String country = locale.getDisplayCountry();

                    if (country.toUpperCase().startsWith(input.toUpperCase()))
                    {
                        choices.add(country);
                        if (choices.size() == 10)
                        {
                            break;
                        }
                    }
                }

                return choices.iterator();
            }
        };
        form.add(field);

        ...more Java here, but not needed for this simple example case...

    }
}

因此,我们在这里看到一个普通的页面,它附加了一个表单。另一方面,该表单包含一个 已进行 Ajax 处理的 文本字段版本。protected Iterator getChoices(String input) 函数是在按下键(通过使用键盘在字段中输入一些值)后由 AJAX 调用(我们稍后会看到) - 意味着该函数是 AJAX 业务逻辑的表示。在这里,我们只检查是否已经输入了内容(用户可能删除了内容),如果是,那么是否存在以已输入字母开头的国家/地区(例如:如果您输入 Aus,它将找到像 Austria 和 Australia 这样的国家/地区)。

最终的 Web 页面将是

<html>
<head>
<script type="text/javascript"><!--/*--><![CDATA[/*><!--*/

var clientTimeVariable = new Date().getTime();

/*-->]]>*/</script>


	...title + css stripped out...
       <script type="text/javascript" src="resources/org.apache.wicket.markup.html.WicketEventReference/wicket-event.js"></script>
       <script type="text/javascript" src="resources/org.apache.wicket.ajax.WicketAjaxReference/wicket-ajax.js"></script>
       <script type="text/javascript" src="resources/org.apache.wicket.ajax.AbstractDefaultAjaxBehavior/wicket-ajax-debug.js"></script>
  
<script type="text/javascript" src="resources/org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteBehavior/wicket-autocomplete.js"></script>
<script type="text/javascript" ><!--/*--><![CDATA[/*><!--*/
Wicket.Event.add(window, "domready", function() { new Wicket.AutoComplete('i1','?wicket:interface=:1:form:ac::IActivePageBehaviorListener:1:&amp;wicket:ignoreIfNotActive=true',false);;});
/*-->]]>*/</script>

</head>
<body>
    
   ...head stripped out...
    

		The textfield below will autocomplete country names. It utilizes AutoCompleteTextField in wicket-extensions.<br/><br/>

		<form action="?wicket:interface=:1:form::IFormSubmitListener::" method="post" id="i2"><div style="display:none"><input type="hidden" name="i2_hf_0" id="i2_hf_0" /></div>
			
			Country: <input value="" autocomplete="off" type="text" size="50" name="ac" onchange="var 
                        wcall=wicketSubmitFormById('i2', '?wicket:interface=:1:form:ac::IActivePageBehaviorListener:3:&amp;wicket:ignoreIfNotActive=true', null,null,null, function() 
                        {return Wicket.$$(this)&amp;&amp;Wicket.$$('i2')}.bind(this));;" id="i1"/>
		</form>

		
<script type="text/javascript"><!--/*--><![CDATA[/*><!--*/

window.defaultStatus='Server parsetime: 0.0070s, Client parsetime: ' + (new Date().getTime() - clientTimeVariable)/1000 +  's';

/*-->]]>*/</script>

</body>
</html>

因此,我们现在得到了一个带有大量 JS 资源(包含 DOM 解析器、转换器等)以及使用 onchange="..." JS 方法对我们的 <input> 字段进行 JS 行为的 HTML。

如果您现在开始在字段中输入一些字符,例如“au”,onchange 事件将被触发,并将调用 wicketSubmitFormById() 方法,发出对服务器的调用并接收 XML。

1  INFO: focus set on i4
2  INFO:
3  INFO: Initiating Ajax GET request on ?wicket:interface=:1:form:ac::IActivePageBehaviorListener:1:&wicket:ignoreIfNotActive=true&q=au&random=0.9530900388300743
4  INFO: Invoking pre-call handler(s)...
5  INFO: Received ajax response (85 characters)
6  INFO:
<ul><li textvalue="Austria">Austria</li><li textvalue="Australia">Australia</li></ul>
7  INFO:

在第 1 行,对字段(这里用 uid i4 表示)的焦点被设置。在我们输入“au”到字段中后,在第 3 行,一个 AJAX 请求被发送到服务器。第 4+5 行说明了预调用处理程序和 AJAX 响应的接收。第 6 行显示了响应的已解码内容,包含一个 <ul>,其中包含以“au”开头的两个预期国家/地区,现在这些国家/地区由 JS 头部库放置在页面上的适当位置。

您现在已经看到了 AJAX 广阔世界中一个小的、简单的例子。要真正理解它,您应该 在线观看和使用它(不要忘记点击右下角的“wicket AJAX 调试”链接,以便您能够看到通信)。在 http://wicketstuff.org/wicket13/ajax/ 中,您将找到更多运行示例,它们都包含代码。

华夏公益教科书