您的位置:首页 > Web前端 > JavaScript

【转】退而求其次的选择1:使用IFrame发送请求《深入理解Ajax:基于JavaScript的RIA开发 》

2010-08-06 22:00 267 查看
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元素:

var rDiv = document.createElement('div');
rDiv.id = 'remotingDiv';
var style = 'border:0;width:0;height:0;';
rDiv.innerHTML = "<iframe name='"+id+"' id='"+id+"' style=""+style+"" mce_style=""+style+""></iframe>";
document.body.appendChild(rDiv);


2 创建一个表单

如果要发起GET请求,只需修改
IFrames中src属性的值,但进行POST请求时则需要使用一个目标表单。GET方法并不是Ajax请求的良好解决方案,主要有两个原因:它能够发
送的数据是有限的(具体的数据量限制取决于浏览器),GET请求会被代理服务器缓存且/或预载入,因此决不要用它来执行诸如数据库更新之类的操作。
在IFrame中使用一个表单是很简单的。只要设置表单的target属性即可,当提交该表单时,其结果就将在该IFrame中载入。以下例子创建了我们的表单,并将其target属性设置为在第2.5.1节中创建的IFrame:
rDiv.form = document.createElement('form');
rDiv.form.setAttribute('id', id+'RemotingForm');
rDiv.form.setAttribute('action', url);
rDiv.form.setAttribute('target', id);
rDiv.form.target = id;
rDiv.form.setAttribute('method', 'post');
rDiv.form.innerHTML = '<input type="hidden" name="data" id="'+id+'Data">';


3 从载入的内容向原始文档发送数据

要知道IFrame的内容已经载入的唯一方
法是在内容页上运行一些JavaScript代码,以提示IFrame所嵌入的父页面。完成该任务的最简单方法是设置载入文档的onload事件句柄。这
一限制意味着使用IFrame不能像使用XMLHttpRequest那样载入任意的内容。不过,当某个页面已被作为Ajax网关时,该方法仍然是很有效
的。以下就是一个onload事件句柄的实例:
<body onload="parent.document.callback(result)">


4 基于IFrame的Ajax完整实例

一个完整的基于IFrame的Ajax实例中的请求包含两个部分内容。第一部分是客户端代码,用来创建IFrame和表单;第二部分是服务器端代码,它负责准备数据,并通过父文档的onload事件句柄将其发送回去。
本例的第1部分(程序清单2-5所示)是位
于一个简单HTML文件中的JavaScript代码。该页面用于测试;回调函数只是在警告对话框中显示出结果。该例子的第2部分(程序清单2-6所示)
是一个简单的PHP脚本,它负责从POST请求中获取数据,并将其回送给父文档。为实现一个实际有效的系统,可能需要在表单中添加一些其他变量,以告诉
PHP代码如何处理上传的数据,或者可以在脚本中直接加入业务逻辑,并对要实现的每个任务都设置一个不同的目标页。

程序清单2-5 使用IFrame发送一个Ajax请求
<html>
<head>
<mce:script type="text/javascript"><!--
var remotingDiv;
function createRemotingDiv(id,url) {
    var rDiv = document.createElement('div');
    rDiv.id = 'remotingDiv';
    var style = 'border:0;width:0;height:0;';
    rDiv.innerHTML = "<iframe name='"+id+"' id='"+id+"' style=""+style+"" mce_style=""+style+""></iframe>";
    document.body.appendChild(rDiv);
    rDiv.iframe = document.getElementById(id);
    rDiv.form = document.createElement('form');
    rDiv.form.setAttribute('id', id+'RemotingForm');
    rDiv.form.setAttribute('action', url);
    rDiv.form.setAttribute('target', id);
    rDiv.form.target = id;
    rDiv.form.setAttribute('method', 'post');
    rDiv.form.innerHTML = '<input type="hidden" name="data" id="'+id+'Data">';
    rDiv.appendChild(rDiv.form);
    rDiv.data = document.getElementById(id+'Data');
    return rDiv;
}
function sendRequest(url,payload,callback) {
    if (!remotingDiv) {
        remotingDiv = createRemotingDiv('remotingFrame', 'blank.html');
    }
    remotingDiv.form.action = url;
    remotingDiv.data.value = payload;
    remotingDiv.callback = callback;
    remotingDiv.form.submit();
}
function test() {
    sendRequest('test.php','This is some test data',
    function(result){ alert(result) });
}
// --></mce:script>
</head>
<body id="body">
<a href="javascript:test()" mce_href="javascript:test()">Test</a>
</body>
</html>


程序清单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>
<head>
<mce:script type="text/javascript"><!--
var result = "<?php echo $_POST['data']; ?>";
// --></mce:script>
</head>
<body onload = "parent.document.getElementById('remotingDiv').callback(result)">
</body>
</html>


在服务器端,该表单将被处理,并将以HTML页面的形式创建输出。添加新数据的最简单方法是生成包含新数据的JavaScript。在这里,我们只是通过
为result变量赋值的方法,将数据回显给客户端。通常,在此会运行服务器端代码,或者输出一个字符(就像本例这样),或者添加将在父文
档中执行的新JavaScript代码。父文档的回调函数是在body标签的onload事件句柄中定义的。

注意:
以上JS代码在插入的时候可能自动添加了mce字样,调试时请自行去除~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐