生病的JavaScript代码
部门项目中,有一个导出功能。业务逻辑如下:根据数据的总记录数和每页大小,分批导出成Excel;如果总记录数大于每页记录数,则出弹出框,让用户选择导出那部分内容,然后导出;如果小于,则直接导出。由于这个功能在很多地方使用,就想写一个通用组件,通过传入必要的参数,调用API就能实现分页下载,不需要多次重复编写这个代码。
为了提高JavaScript的执行效率(更多内容请看:高性能JavaScript),提高代码的内聚性,将必要的代码和逻辑都对外封装起来,我决定使用“面向对象思想”来“组织”这段JavaScript代码。(关于在JavaScript中如何使用“面向对象思想”,以后会专门发文来讲解。)另外,部门使用的是ExtJS框架,所以就使用这个框架的组件展示弹出框以及相关的组件。
代码花了一天写完;由于“闭包”等问题,花了两天来调试。结果,还是报错。看来真是生病了,而且病的不轻。奈何我这个攻城师“医生”水平有限,一直不能很好“治愈”这个问题。所以,请大家帮忙看看如何“治疗”这个问题。
JavaScript代码如下:
/** * @Function: PagingDownloader * @Description: 分页下载工具 * * @param: baseUrl 基础的URL * @param: params 参数对象 * @param: totalCount 总的记录数 * * @param: countPerPage 下载时,每页大小。这个参数可选。如果不传,默认是20000. * @param: pageParamsKey 分页相关参数的Key数组。例如分页的URL是start=0&limit=20,这里的pageParamsKey就是start和limit,传参数是即传["start", "limit"]。这个参数可选,如果不传,默认是["start", "limit"]。注意:数组中,第一个是"开始索引"相关的Key名称;第二个参数是页面大小相关的Key名称 * * @version: 1.0 * @author: D瓜哥, http://www.diguage.com/ * @date: 创建时间 2012年8月30日 11:05:57 * * Modification History: * Date Author Version Description *---------------------------------------------------------* * 修改时间 修改人 版本 修改原因 */ function PagingDownloader(baseUrl, params, totalCount, countPerPage, pageParamsKey){ this.baseUrl = baseUrl; this.params = params; this.totalCount = totalCount; var argLength = arguments.length; //如果有四个参数,则判断第四个参数的类型,如果是数字则认为是设置页面大小;如果是Object,可以 if(argLength > 3 && typeof arguments[3] === "number"){ this.countPerPage = arguments[3]; } if(argLength > 3 && typeof arguments[3] === "object"){ this.pageParamsKey = arguments[3]; } //如果有五个参数,则认为是把所有的参数都传了,最后一个参数就是自定义"分页相关的Key"。 if(argLength > 4 && typeof arguments[4] === "object"){ this.pageParamsKey = arguments[4]; } } PagingDownloader.prototype = { constructor: PagingDownloader, //初始化默认的页面大小 countPerPage: 20000, //初始化默认的分页参数的Key名称。 pageParamsKey: ["start", "limit"], //根据传入的参数,获取Ext.form.ComboBox所需的数据。 getComboBoxData: function() { var times = Math.ceil(this.totalCount / this.countPerPage); var array = new Array(); for (var index = 1; index <= times; index++) { if (index < times) { var arr = new Array(); arr.push((index - 1) * this.countPerPage); arr.push("第" + index + "批,(" + (index - 1) * this.countPerPage + 1 + "至" + index * this.countPerPage + ")"); array.push(arr); } else { var arr = new Array(); arr.push((index - 1) * this.countPerPage); arr.push("第" + index + "批,(" + (index - 1) * this.countPerPage + 1 + "至" + this.totalCount + ")"); array.push(arr); } } return array; }, //根据传入参数以及计算出来的分页参数值,创建下载的URL。(由于闭包问题,不引用这个"类"的局部变量,把所有的参数都出入进去。) createDownloadUrl: function(baseUrl, params, pageParamsKey, start, limit){ params[pageParamsKey[0]] = start; if(arguments.length > 4){ params[pageParamsKey[1]] = arguments[4]; }else{ params[pageParamsKey[1]] = this.countPerPage; } var resultUrl = baseUrl + "?"; for(var p in params){ resultUrl += p + "=" + params[p] + "&"; } // alert(resultUrl.substring(0, resultUrl.length-1)); return resultUrl.substring(0, resultUrl.length-1); }, download: function(){ if (this.totalCount > this.countPerPage) { //创建一个下载Hook var pdHelper = document.createElement("div"); pdHelper.setAttribute("id","pageDownloaderHook"); document.body.appendChild(pdHelper); //为了避免闭包问题,在这里把ComboBoxData取出来,放到变量中。 var batchData = this.getComboBoxData(); //为了避免闭包问题,把Ext.form.ComboBox创建出来,放到变量中。 var pageComboBox = new Ext.form.ComboBox({ store : new Ext.data.SimpleStore({ data : batchData, fields : ['value', 'text'] }), displayField : 'text', valueField : 'value', triggerAction : 'all', mode : 'local', value : 0 }); var panel = new Ext.Window({ width : 300, height : 200, modal : true, plain : true, title : '导出选项', items : [{ xtype : "label", text : "数据太大,需要分批导出,每批数量" + this.countPerPage + "条" }, pageComboBox], buttons : [{ text : "导出", //因为闭包问题。所以,需要把这些值,作为这个Button的"配置项"传入进去。 baseUrl: this.baseUrl, urlParams: this.params, pageParamsKey: this.pageParamsKey, countPerPage: this.countPerPage, createDownloadUrl: this.createDownloadUrl, handler : function(button) { var start = pageComboBox.getValue(); //这样就可以从button获取上面转入的一些值,从而避免闭包问题。同时,将createDownloadUrl方法改为传参数(而不是通过this获取参数值),也是因为这里的闭包访问不到外面的方法。 var exportUrl = button.createDownloadUrl(button.baseUrl, button.urlParams, button.pageParamsKey, start, button.countPerPage); alert(exportUrl); var loadMask=new Ext.LoadMask(Ext.getBody(), {msg:"正在加载数据……",removeMask:true}); loadMask.show(); var downloadElement=document.getElementById("pageDownloaderHook"); downloadElement.src = exportUrl; downloadElement.onreadystatechange=function(){ if(downloadElement.readyState=='interactive') {loadMask.hide()}; } } }, { text : "取消", handler : function() { try { panel.close(); } catch (e) { } } }] }); //执行到这里报错!同时,点击选择框也报错。请帮忙解决这个问题。 panel.show(); } else { alert(this.totalCount + " > " + this.countPerPage + ":" +(this.totalCount > this.countPerPage) +", "+this.createDownloadUrl(this.baseUrl, this.params, this.pageParamsKey, 0, this.totalCount)); //这里没有闭包问题,可以通过this正常使用这些函数以及参数值。 window.location = this.createDownloadUrl(this.baseUrl, this.params, this.pageParamsKey, 0, this.totalCount); } } }
测试的HTML代码如下:(注意:需要在HTML中加上ExtJS库)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>分页下载工具测试页面</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <!--请导入ExtJS库的必要文件--> <!--请根据自己的实际路径,修改引入的路径。--> <script type="text/javascript" src="./PagingDownloader.js"></script> <script type="text/javascript"> Ext.onReady(function(){ //分页下载工具测试 new PagingDownloader("myBaseUrl", {a:"aba", b:123, c:"ab32"}, 75000, 30000, ["startPage", "size"]).download(); }); </script> </head> <body> 页面工具下载测试页面<br> </body> </html>
从“IE8浏览器的开发者”中可以看出,在执行PagingDownloader.js的160行报错。不过奇怪的是,如果这里执行如下的隐藏代码不会报错!!
panel.show();
想来很久,不知道这个问题是怎么回事,也不知道如何解决。实在没辙,只好发出来,希望擅长的朋友帮忙解决一下。谢谢!!
作 者: D瓜哥,https://www.diguage.com/
原文链接:https://wordpress.diguage.com/archives/52.html
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。
原文链接:https://wordpress.diguage.com/archives/52.html
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。
代码文本写的挺好看的,你用的是什么主题,是eclipse吗?
怎么修改代码中字体的大小啊。
代码高亮使用的是SyntaxHighligter,我的有篇文章做了详细介绍:http://www.diguage.com/archives/59.html。颜色主题是默认的。另外,不清楚怎么修改代码中的字体大小。这个一般不用改吧,目前的大小已经可以接收了。哈哈
代码文本写的挺好看的,你用的是什么主题,