生病的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。颜色主题是默认的。另外,不清楚怎么修改代码中的字体大小。这个一般不用改吧,目前的大小已经可以接收了。哈哈
代码文本写的挺好看的,你用的是什么主题,