IFrames为异步调用提供了一个合适的 传输途径,因为它们可以在不使整个页面重新装载的基础上载入新内容,而新的IFrame元素则可以通过JavaScript创建。IFrame最好的属性 之一是表单可以将其作为目标,从而只需重载IFrame而不用对整个页面进行重载; 该方法可以通过POST类型请求将大量数据发送给服务器。
在使用IFrame作为传输方法时,其中的 一个难点是载入的页面必须是HTML格式的,并且在载入完成时,需要通过JavaScript的onload事件句柄来告诉其父文档。这就使得基于 IFrames发出的所有请求所针对的页面都必须是针对IFrame请求设计的(其代码无法像在XMLHttpRequest方法中那样获取一个XML文 件)。
注意,使用IFrames还有许多其他限制:
· 只支持异步请求;
· 需要修改服务器端页面;
· 会在浏览器的历史中加上虚构的项;
· 在某些浏览器上,会使后退、前进按钮的行为变得不确定;
· 在不同浏览器中的实现有巨大的不同,特别是在老版本的浏览器中。
IFrame和 XMLHttpRequest相比也有一个优点,即可以用来完成文件上传。由于浏览器的安全限制,只有诸如单击表单的用户操作可以与用户机器上的文件交 互。可以仅对文件上传使用目标为一个IFrame的表单,它不涉及常规的表单POST操作和页面重载周期。不过,这不是针对文件上传使用IFrame,而 对其他Ajax请求则使用XMLHttpRequest的理由。除非发起的是远程脚本风格的Ajax请求(这将在第3章中讲述),对于IFrame的限 制,会使所有Ajax开发项目的工作量大大增加。
1 创建一个隐藏IFrame
为了最大程度上与老版本浏览器兼容,可以在HTML中添加IFrame并将其大小设置为0x0(不能仅是隐藏它,否则有些浏览器将不会载入它)。不过该方 法的灵活性并不好,因此应该动态地创建这个帧。并非所有老版本的浏览器都支持document.createElement方法,但不支持该方法的浏览器 通常也不具备在载入数据时所需的其他动态能力,因此对于它们最好是提供一个静态HTML版本的页面。在下面的例子中,使用innerHTML创建了这个 IFrame,因为它比使用DOM方法更简单。注意,这里也使用了document.createElement方法,用来添加div元素:
2 创建一个表单
如果要发起GET请求,只需修改 IFrames中src属性的值,但进行POST请求时则需要使用一个目标表单。GET方法并不是Ajax请求的良好解决方案,主要有两个原因:它能够发 送的数据是有限的(具体的数据量限制取决于浏览器),GET请求会被代理服务器缓存且/或预载入,因此决不要用它来执行诸如数据库更新之类的操作。
在IFrame中使用一个表单是很简单的。只要设置表单的target属性即可,当提交该表单时,其结果就将在该IFrame中载入。以下例子创建了我们的表单,并将其target属性设置为在第2.5.1节中创建的IFrame:
3 从载入的内容向原始文档发送数据
要知道IFrame的内容已经载入的唯一方 法是在内容页上运行一些JavaScript代码,以提示IFrame所嵌入的父页面。完成该任务的最简单方法是设置载入文档的onload事件句柄。这 一限制意味着使用IFrame不能像使用XMLHttpRequest那样载入任意的内容。不过,当某个页面已被作为Ajax网关时,该方法仍然是很有效 的。以下就是一个onload事件句柄的实例:
4 基于IFrame的Ajax完整实例
一个完整的基于IFrame的Ajax实例中的请求包含两个部分内容。第一部分是客户端代码,用来创建IFrame和表单;第二部分是服务器端代码,它负责准备数据,并通过父文档的onload事件句柄将其发送回去。
本例的第1部分(程序清单2-5所示)是位 于一个简单HTML文件中的JavaScript代码。该页面用于测试;回调函数只是在警告对话框中显示出结果。该例子的第2部分(程序清单2-6所示) 是一个简单的PHP脚本,它负责从POST请求中获取数据,并将其回送给父文档。为实现一个实际有效的系统,可能需要在表单中添加一些其他变量,以告诉 PHP代码如何处理上传的数据,或者可以在脚本中直接加入业务逻辑,并对要实现的每个任务都设置一个不同的目标页。
程序清单2-5 使用IFrame发送一个Ajax请求
程序清单2-5中包含3个函数:
· createRemotingDiv 用来设置IFrame。
· sendRequest 用来发起Ajax请求。
· test 发起Ajax请求。test函数在页面的HTML代码中与一个链接绑定在一起。用户点击该链接,将启动一个Ajax请求。
函数 createRemotingDiv中所包含的代码在前面已经描述过了,它包括的代码用来创建隐藏IFrame以及将向其提交信息的表 单。在表单创建完后,其目标将是新创建的IFrame,用表单提交代替当前页面的重载。开发时,经常在调试过程中显示IFrame,这是很有效的,因为可 以看到调用的页面所生成的输出。要实现该目标,可以将第8行修改为“width:200;height:200”。
函数sendRequest用来发起Ajax请求。其参数包括请求将发向的URL、发送给服务器的payload,以及请求完成时将执行的回调函数。该函数使用 createRemotingDiv来配置这一过程。然后sendRequest将更新IFrame表单的操作,把 payload值填充到表单中,使用IFrame提交该表单。当在IFrame中载入了新页面时,新文档将通过JavaScript的onload句柄调 用已传给sendRequest方法的回调函数。这个处理POST表单的PHP页面,以及创建onload句柄的JavaScript代码如程序清单 2-6所示。
程序清单2-6 处理基于IFrame的Ajax请求的PHP服务器端页面
在服务器端,该表单将被处理,并将以HTML页面的形式创建输出。添加新数据的最简单方法是生成包含新数据的JavaScript。在这里,我们只是通过 为result变量赋值的方法,将数据回显给客户端。通常,在此会运行服务器端代码,或者输出一个字符(就像本例这样),或者添加将在父文 档中执行的新JavaScript代码。父文档的回调函数是在body标签的onload事件句柄中定义的。
注意: 以上JS代码在插入的时候可能自动添加了mce字样,调试时请自行去除~