前面描述了如何在服务器端生成HTML表格,本节就讲述如何在客户端完成同样的工作。在客户端实现这个功能,需要用到ScriptMethod方法,将XmlDocument返回到客户端,客户端使用JavaScript脚本来完成表格的渲染工作。
先实现服务器端的WebService,假定为ReadDataService.asmx。其实现大致如下:
using System.Xml; using System.Xml; ... /// <summary> /// Summary description for MyService /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService] public class ReadDataService: System.Web.Services.WebService { [WebMethod] [ScriptMethod(ResponseFormat = ResponseFormat.Xml)] public XmlDocument read(string excelFile) // 这里直接使用文件名作为参数,实际应用中应该使用其它参数,如id之类,否则可能有安全上的问题 { XmlDocument xml = new XmlDocument(); xml.LoadXml("<?xml version=/"1.0/" encoding=/"utf-8/" ?><Data></Data>"); // 填充xml的过程略 ... return xml; // 结果 } ... }
在页面上还需要加入对WebService的引用,也可以加到MasterPage中:
<ajaxToolkit:ToolkitScriptManager ID="ScriptManager1" runat="server" > <Services> <asp:ServiceReference Path="ReadDataService.asmx" /> </Services> </ajaxToolkit:ToolkitScriptManager>
在客户端这样通过JavaScript脚本调用WebService的方法:
ReadDataService.read(onReadDataSucceeded, onReadDataFailed, 'xmlDocument');
onReadDataSucceeded和onReadDataFailed分别处理调用成功和失败事件。我们在成功时生成表格,失败则给出提示:
// result是服务器返回的结果 // context是指定的上下文,这里是'xmlDocument' // methodName则是read,我们的ReadDataService.read方法的名字 function onReadDataSucceeded(result, context, methodName) { readTicks = getMilliseconds() - readTicks; // 这个时间现在在10秒内,在我的示例中大致为7.3-7.5秒之间 //alert('Time consumption:' + (readTicks / 1000.0) + ' seconds'); if ( document.all ) // IE { for(var sheet_idx = 0; sheet_idx < result.documentElement.childNodes.length; sheet_idx++) // 遍历工作表 { var sheet_node = result.documentElement.childNodes[sheet_idx]; // 工作表节点 var _rowNum = 1, // 工作表行列数 _colNum = 1, sheetName = ''; // 工作表名 var table = document.createElement('TABLE'); // 创建新表 table.id = 'Sheet_' + sheet_idx; // 表名 // 设置单元格样式 table.style.borderCollapse = 'collapse'; table.style.tableLayout = 'fixed'; table.style.border = '1px solid black'; // 设置单元格属性 table.cellPadding = 0; table.cellSpacing = 0; for(var attr_idx = 0; attr_idx < sheet_node.attributes.length; attr_idx++) { var attr = sheet_node.attributes[attr_idx]; switch(attr.nodeName) { case 'name': sheetName = attr.nodeValue; break; case 'width': table.style.width = attr.nodeValue + 'pt'; break; // 宽度 case 'row': _rowNum = parseInt(attr.nodeValue); break; // 行,列数 case 'col': _colNum = parseInt(attr.nodeValue); break; } } // 将工作表添加到document if ( document.sheet ) document.sheet[document.sheet] = { 'table': table.id, 'name': sheetName }; else document.sheet = [{ 'table': table.id, 'name': sheetName }]; // 工作表名称 var sheetNameRow = table.insertRow(); var sheetNameCell = sheetNameRow.insertCell(); initHeaderCell(sheetNameCell); sheetNameCell.colSpan = _colNum + 1; sheetNameCell.innerText = sheetName; sheetNameCell.style.width = table.style.width; // 添加列头 var colHeaderRow = table.insertRow(); for(var col_idx = 0; col_idx <= _colNum; col_idx++ ) { var cell = colHeaderRow.insertCell(); //col_idx); if ( col_idx > 0 ) cell.innerText = getColLabel(col_idx); else cell.innerText = ' '; // 第一个单元格! initHeaderCell(cell); } for(var row_idx = 0; row_idx < sheet_node.childNodes.length; row_idx++ ) // 遍历行 { var row = table.insertRow() // row_idx + 1); // 插入行 {// 插入行标头 var rowHeaderCell = row.insertCell(); //0); initHeaderCell(rowHeaderCell); rowHeaderCell.innerText = row_idx + 1; //row.rowIndex; } var row_node = sheet_node.childNodes[row_idx]; // 行节点 for(var attr_idx = 0; attr_idx < row_node.attributes.length; attr_idx++ ) // 遍历属性,设置行高 { var attr = row_node.attributes[attr_idx]; // 获取行属性 switch(attr.nodeName) { case "height": row.height = attr.nodeValue; break; // 高度 } } if ( row_node.childNodes.length == 0 ) // 没有单元格,是一个空行 { for(var i = 1; i <= _colNum; i++ ) // 插入空单元格 { initEmptyCell(row.insertCell()); //i)); } } else for(var cell_idx = 0; cell_idx < row_node.childNodes.length; cell_idx++ ) // 遍历列 { var cell_node = row_node.childNodes[cell_idx]; // 单元格节点 var prev_cell_node = cell_node.previousSibling; // 前一个节点 var cellProp = { // 单元格属性 'row': 0, 'col': 0, 'rowspan': 1, 'colspan': 1, 'hasFormula': false, 'formula': '', 'value2': '', 'weight': '', 'height': '', 'font-family': '', 'font-size': '', 'font-color': '', 'font-bold': false, 'font-italic': false, 'font-strikethrough': false, 'align': '', 'valign': '' };
// 获取单元格属性 for(var attr_idx = 0; attr_idx < cell_node.attributes.length; attr_idx++ ) { var attr = cell_node.attributes[attr_idx]; cellProp[attr.nodeName] = attr.nodeValue; } // 从XML解析出来的数据会成为字符串,因此需要修正为number,否则下文的补完计划会出错 cellProp.col = parseInt(cellProp.col); cellProp.rowspan = parseInt(cellProp.rowspan); cellProp.colspan = parseInt(cellProp.colspan); if ( prev_cell_node ) // 如果前一个节点存在,可能需要补完中间的空白 { var prevColIdx = 0, // 前一个节点的单元号和 prevColSpan = 1;
for(var attr_idx = 0; attr_idx < prev_cell_node.attributes.length; attr_idx++ ) // 获取前一单元格的属性 { var attr = prev_cell_node.attributes[attr_idx]; switch(attr.nodeName) { case 'col' : prevColIdx = parseInt(attr.nodeValue); break; // 列号 case 'colspan' : prevColSpan = parseInt(attr.nodeValue); break; // 列跨度 } } if (prevColIdx + prevColSpan < cellProp.col) // 如果中间有空,则插入 { for ( var i = prevColIdx + prevColSpan; i < cellProp.col; i++) { initEmptyCell(row.insertCell()); //i)); // 补完空洞 } } } else { if ( cellProp.col > 1 ) // 如果不是第1个单元格(从0开始为列标头),需要补完 { for ( var i = 1; i < cellProp.col; i++ ) initEmptyCell(row.insertCell(i)); // 补完空洞 } } // 插入单元格 var cell = row.insertCell(); // 设置属性 cell.align = cellProp.align; cell.valign = cellProp.valign; cell.width = cellProp.width; cell.height = cellProp.height; cell.style.color = cellProp['font-color']; cell.style.fontFamily = cellProp['font-family']; cell.style.fontSize = cellProp['font-size']; cell.style.fontWeight = cellProp['font-bold'] == 'true' ? 'bold' : ''; cell.style.border = '1px solid black'; cell.colSpan = cellProp.colspan; cell._rowspan = cellProp.rowspan; // 设置数据域 cell.hasFormula = cellProp.hasFormula; cell.formula = cellProp.formula; cell.dataField = cell.innerText = cellProp.value2; // 如果没有后续节点,表明是最后一个单元格,此时需要补完,使之具有_colNum个列 if (cell_node.nextSibling == null && cellProp.col + cellProp.colspan <= _colNum) { for ( var i = cellProp.col + cellProp.colspan; i <= _colNum; i++ ) initEmptyCell(row.insertCell()); //i)); // 插入空单元格 } } // for cell } // for row setAllCellTip(table); document.body.appendChild(table); } // for sheet } else { // fireFox // 留待同学课后作业 } }
function onReadDataFailed(error) // 提示处理错误 { var stackTrace = error.get_stackTrace(); var message = error.get_message(); var statusCode = error.get_statusCode(); var exceptionType = error.get_exceptionType(); var timedout = error.get_timedOut(); // Display the error. alert( "Stack Trace: " + stackTrace + "<br/>" + "Service Error: " + message + "<br/>" + "Status Code: " + statusCode + "<br/>" + "Exception Type: " + exceptionType + "<br/>" + "Timedout: " + timedout);}
至此为至,客户端生成表格的工作也完成了。