生病的JavaScript代码
部门项目中,有一个导出功能。业务逻辑如下:根据数据的总记录数和每页大小,分批导出成Excel;如果总记录数大于每页记录数,则出弹出框,让用户选择导出那部分内容,然后导出;如果小于,则直接导出。由于这个功能在很多地方使用,就想写一个通用组件,通过传入必要的参数,调用API就能实现分页下载,不需要多次重复编写这个代码。
为了提高JavaScript的执行效率(更多内容请看:高性能JavaScript),提高代码的内聚性,将必要的代码和逻辑都对外封装起来,我决定使用“面向对象思想”来“组织”这段JavaScript代码。(关于在JavaScript中如何使用“面向对象思想”,以后会专门发文来讲解。)另外,部门使用的是ExtJS框架,所以就使用这个框架的组件展示弹出框以及相关的组件。
代码花了一天写完;由于“闭包”等问题,花了两天来调试。结果,还是报错。看来真是生病了,而且病的不轻。奈何我这个攻城师“医生”水平有限,一直不能很好“治愈”这个问题。所以,请大家帮忙看看如何“治疗”这个问题。
JavaScript代码如下:
001 | /** |
002 | * @Function: PagingDownloader |
003 | * @Description: 分页下载工具 |
004 | * |
005 | * @param: baseUrl 基础的URL |
006 | * @param: params 参数对象 |
007 | * @param: totalCount 总的记录数 |
008 | * |
009 | * @param: countPerPage 下载时,每页大小。这个参数可选。如果不传,默认是20000. |
010 | * @param: pageParamsKey 分页相关参数的Key数组。例如分页的URL是start=0&limit=20,这里的pageParamsKey就是start和limit,传参数是即传["start", "limit"]。这个参数可选,如果不传,默认是["start", "limit"]。注意:数组中,第一个是"开始索引"相关的Key名称;第二个参数是页面大小相关的Key名称 |
011 | * |
012 | * @version: 1.0 |
013 | * @author: D瓜哥, http://www.diguage.com/ |
014 | * @date: 创建时间 2012年8月30日 11:05:57 |
015 | * |
016 | * Modification History: |
017 | * Date Author Version Description |
018 | *---------------------------------------------------------* |
019 | * 修改时间 修改人 版本 修改原因 |
020 | */ |
021 |
022 | function PagingDownloader(baseUrl, params, totalCount, countPerPage, pageParamsKey){ |
023 | this .baseUrl = baseUrl; |
024 | this .params = params; |
025 | this .totalCount = totalCount; |
026 | var argLength = arguments.length; |
027 |
028 | //如果有四个参数,则判断第四个参数的类型,如果是数字则认为是设置页面大小;如果是Object,可以 |
029 | if (argLength > 3 && typeof arguments[3] === "number" ){ |
030 | this .countPerPage = arguments[3]; |
031 | } |
032 | if (argLength > 3 && typeof arguments[3] === "object" ){ |
033 | this .pageParamsKey = arguments[3]; |
034 | } |
035 | |
036 | //如果有五个参数,则认为是把所有的参数都传了,最后一个参数就是自定义"分页相关的Key"。 |
037 | if (argLength > 4 && typeof arguments[4] === "object" ){ |
038 | this .pageParamsKey = arguments[4]; |
039 | } |
040 | } |
041 |
042 | PagingDownloader.prototype = { |
043 | constructor: PagingDownloader, |
044 | //初始化默认的页面大小 |
045 | countPerPage: 20000, |
046 | |
047 | //初始化默认的分页参数的Key名称。 |
048 | pageParamsKey: [ "start" , "limit" ], |
049 | |
050 | //根据传入的参数,获取Ext.form.ComboBox所需的数据。 |
051 | getComboBoxData: function () { |
052 | var times = Math.ceil( this .totalCount / this .countPerPage); |
053 | var array = new Array(); |
054 | for ( var index = 1; index <= times; index++) { |
055 | if (index < times) { |
056 | var arr = new Array(); |
057 | arr.push((index - 1) * this .countPerPage); |
058 | arr.push( "第" + index + "批,(" + (index - 1) * this .countPerPage + 1 |
059 | + "至" + index * this .countPerPage + ")" ); |
060 | array.push(arr); |
061 | } else { |
062 | var arr = new Array(); |
063 | arr.push((index - 1) * this .countPerPage); |
064 | arr.push( "第" + index + "批,(" + (index - 1) * this .countPerPage + 1 |
065 | + "至" + this .totalCount + ")" ); |
066 | array.push(arr); |
067 | } |
068 | |
069 | } |
070 | return array; |
071 | }, |
072 | |
073 | //根据传入参数以及计算出来的分页参数值,创建下载的URL。(由于闭包问题,不引用这个"类"的局部变量,把所有的参数都出入进去。) |
074 | createDownloadUrl: function (baseUrl, params, pageParamsKey, start, limit){ |
075 | params[pageParamsKey[0]] = start; |
076 | if (arguments.length > 4){ |
077 | params[pageParamsKey[1]] = arguments[4]; |
078 | } else { |
079 | params[pageParamsKey[1]] = this .countPerPage; |
080 | } |
081 | |
082 | var resultUrl = baseUrl + "?" ; |
083 | for ( var p in params){ |
084 | resultUrl += p + "=" + params[p] + "&" ; |
085 | } |
086 | // alert(resultUrl.substring(0, resultUrl.length-1)); |
087 | return resultUrl.substring(0, resultUrl.length-1); |
088 | }, |
089 | |
090 | download: function (){ |
091 | if ( this .totalCount > this .countPerPage) { |
092 | //创建一个下载Hook |
093 | var pdHelper = document.createElement( "div" ); |
094 | pdHelper.setAttribute( "id" , "pageDownloaderHook" ); |
095 | document.body.appendChild(pdHelper); |
096 | |
097 | //为了避免闭包问题,在这里把ComboBoxData取出来,放到变量中。 |
098 | var batchData = this .getComboBoxData(); |
099 | |
100 | //为了避免闭包问题,把Ext.form.ComboBox创建出来,放到变量中。 |
101 | var pageComboBox = new Ext.form.ComboBox({ |
102 | store : new Ext.data.SimpleStore({ |
103 | data : batchData, |
104 | fields : [ 'value' , 'text' ] |
105 | }), |
106 | displayField : 'text' , |
107 | valueField : 'value' , |
108 | triggerAction : 'all' , |
109 | mode : 'local' , |
110 | value : 0 |
111 | }); |
112 | |
113 | var panel = new Ext.Window({ |
114 | width : 300, |
115 | height : 200, |
116 | modal : true , |
117 | plain : true , |
118 | title : '导出选项' , |
119 | items : [{ |
120 | xtype : "label" , |
121 | text : "数据太大,需要分批导出,每批数量" + this .countPerPage + "条" |
122 | }, pageComboBox], |
123 | buttons : [{ |
124 | text : "导出" , |
125 | |
126 | //因为闭包问题。所以,需要把这些值,作为这个Button的"配置项"传入进去。 |
127 | baseUrl: this .baseUrl, |
128 | urlParams: this .params, |
129 | pageParamsKey: this .pageParamsKey, |
130 | countPerPage: this .countPerPage, |
131 | createDownloadUrl: this .createDownloadUrl, |
132 | |
133 | handler : function (button) { |
134 | var start = pageComboBox.getValue(); |
135 | //这样就可以从button获取上面转入的一些值,从而避免闭包问题。同时,将createDownloadUrl方法改为传参数(而不是通过this获取参数值),也是因为这里的闭包访问不到外面的方法。 |
136 | var exportUrl = button.createDownloadUrl(button.baseUrl, button.urlParams, button.pageParamsKey, start, button.countPerPage); |
137 | alert(exportUrl); |
138 | var loadMask= new Ext.LoadMask(Ext.getBody(), {msg: "正在加载数据……" ,removeMask: true }); |
139 | loadMask.show(); |
140 | var downloadElement=document.getElementById( "pageDownloaderHook" ); |
141 | downloadElement.src = exportUrl; |
142 | downloadElement.onreadystatechange= function (){ |
143 | if (downloadElement.readyState== 'interactive' ) |
144 | {loadMask.hide()}; |
145 | } |
146 | } |
147 | }, { |
148 | text : "取消" , |
149 | handler : function () { |
150 | try { |
151 | panel.close(); |
152 | } catch (e) { |
153 | } |
154 | } |
155 | }] |
156 | |
157 | }); |
158 | |
159 | //执行到这里报错!同时,点击选择框也报错。请帮忙解决这个问题。 |
160 | panel.show(); |
161 | |
162 | } else { |
163 | alert( this .totalCount + " > " + this .countPerPage + ":" +( this .totalCount > this .countPerPage) |
164 | + ", " + this .createDownloadUrl( this .baseUrl, this .params, this .pageParamsKey, 0, this .totalCount)); |
165 | //这里没有闭包问题,可以通过this正常使用这些函数以及参数值。 |
166 | window.location = this .createDownloadUrl( this .baseUrl, this .params, this .pageParamsKey, 0, this .totalCount); |
167 | } |
168 | } |
169 | } |
测试的HTML代码如下:(注意:需要在HTML中加上ExtJS库)
01 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
02 | < html > |
03 | < head > |
04 | < title >分页下载工具测试页面</ title > |
05 | < meta http-equiv = "pragma" content = "no-cache" > |
06 | < meta http-equiv = "cache-control" content = "no-cache" > |
07 | < meta http-equiv = "expires" content = "0" > |
08 | <!--请导入ExtJS库的必要文件--> |
09 | <!--请根据自己的实际路径,修改引入的路径。--> |
10 | < script type = "text/javascript" src = "./PagingDownloader.js" ></ script > |
11 | |
12 | < script type = "text/javascript" > |
13 | Ext.onReady(function(){ |
14 | //分页下载工具测试 |
15 | new PagingDownloader("myBaseUrl", {a:"aba", b:123, c:"ab32"}, 75000, 30000, ["startPage", "size"]).download(); |
16 | }); |
17 | </ script > |
18 |
19 | </ head > |
20 | |
21 | < body > |
22 | 页面工具下载测试页面< br > |
23 | </ body > |
24 | </ html > |
从“IE8浏览器的开发者”中可以看出,在执行PagingDownloader.js的160行报错。不过奇怪的是,如果这里执行如下的隐藏代码不会报错!!
1 | 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。颜色主题是默认的。另外,不清楚怎么修改代码中的字体大小。这个一般不用改吧,目前的大小已经可以接收了。哈哈
代码文本写的挺好看的,你用的是什么主题,