利用iframe与Response.Flush实现进度展示效果
开发中经常碰到要处理很多数据的情况,然后希望在客户端展示当前的处理进度。之前有碰到客户端界面展示一个类似excel的报表,然后用户插入一批数据,然后点击保存后将所有数据一条条插入到数据库同时展示当前数据的处理结果。为了简便下面的代码已简单为主。
方式1:就是获取一条数据,然后发一个Ajax请求,等返回结果然后继续处理下一条,再发一个Ajax请求,循环往复,但是这样就需要多少的请求啊……
方式2:利用Response.Flush方法,第一次将全部的数据post到服务器,然后每次处理一条,利用Flush功能输出结果到客户端,这样就相当其实只有一个请求,然后浏览器一个接收数据,直到所有处理完成Response.Close下返回一个200的状态码
返现结果并不是我想象的那样,console.log只会在全部处理完毕以后再输出,奇怪了,firebug展示的响应结果是一直在不停向客户端输出的呀,好吧第一反应是jquery的success只会在返回200状态码后才会回调的,那Flush反悔的是什么状态码呢?好吧,哥不要你了,我用原生的ajax总行了吧,怎么说记得有一个onreadystatechage的方法,然后还有一个叫readyState的东东表示当前的状态,
//0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法)
// 1 (初始化) 对象已建立,尚未调用send方法
// 2 (发送数据) send方法已调用,但是当前的状态及http头未知
// 3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误,
// 4 (完成) 数据接收完毕,此时可以通过通过responseBody和responseText获取完整的回应数据
确实有一个3表示数据传送中,表示接收部分数据,可是又郁闷了,此时因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误,得!看来不能用ajax了。好吧用iframe吧,直接写代码了
主页面Default.aspx提交
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="myproject1._Default" %> <!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" > <head runat="server"> <title>无标题页</title> <style type="text/css"> #process{width:200px; height:20px; border:1px solid #ddd; position:relative; margin-bottom:5px;} #cur_process{width:0px; height:20px; background:green;} #cur_process_num{ position:absolute;left:0px; top:0px;} #postiframe{display:none;} #button1{background:#ddd; border:1px solid #aaa;} </style> </head> <body> <form id="form1" runat="server"> <div> <div id="process"><div id="cur_process"></div><div id="cur_process_num"></div></div> <iframe id="postiframe" name="postiframe" src="WebForm1.aspx" ></iframe> <input type="button" id="button1" value="提交" onclick="submitit();" /> </div> </form> <script src="jquery-1.4.2.min.js" type="text/javascript"></script> <script type="text/javascript"> var cur, cur_num; //后台回调方法 function callBack(num) { (cur || (cur = $('#cur_process'))).width(num * 2 + 'px'); (cur_num || (cur_num = $('#cur_process_num'))).html(num + '%'); } //开始提交 function submitit() { var conW = document.getElementById('postiframe').contentWindow; conW.document.forms['postform'].submit(); } </script> </body> </html>
处理页面WebForm1.aspx前台,注意将其form的target指向父页面default.aspx的iframe
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="myproject1.WebForm1" %> <!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" > <head runat="server"> <title>无标题页</title> </head> <body> <form runat="server" id="postform" name="postform" target="postiframe"> <div> <input type="hidden" name="cur_method" value="add" id="cur_method"/> </div> </form> </body> </html>
处理页面WebForm1.aspx.cs后台
public partial class WebForm1 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string m = Request.Form["cur_method"]; if (!string.IsNullOrEmpty(m) && m == "add") { StringBuilder strBuilder = new StringBuilder(); for (var j = 0; j <=24; j++) { strBuilder.Append(" ");//因为IE浏览器下flush必须达到256字节才能生效,所以无奈加上这个 } string str = strBuilder.ToString(); for (int i = 1; i <= 100; i = i + 1) { Response.Clear(); Response.Write("<script type=\"text/javascript\">parent.callBack('" + i + "');" + str + "</script>");//输出当前处理进度回调父页面的js Response.Flush();//输出到浏览器端 Thread.Sleep(100);//模拟处理中 } Response.Close(); } } }