首页 > Web开发, 挨踢(IT) > 生病的JavaScript代码

生病的JavaScript代码

2012年9月25日 发表评论 阅读评论 895 人阅读    

  部门项目中,有一个导出功能。业务逻辑如下:根据数据的总记录数和每页大小,分批导出成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瓜哥,http://www.diguage.com/
原文链接:http://www.diguage.com/archives/52.html
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。



如果感觉这篇文章不错,请点击这里的分享按钮,分享到微博等地方去,让更多人受益!
您的支持是D瓜哥最大的写作动力!谢谢!

  1. 灯塔
    2014年2月9日22:18 | #1

    代码文本写的挺好看的,你用的是什么主题,是eclipse吗?

  2. 2014年2月9日23:41 | #2

    怎么修改代码中字体的大小啊。

    • 2014年2月22日11:26 | #3

      代码高亮使用的是SyntaxHighligter,我的有篇文章做了详细介绍:http://www.diguage.com/archives/59.html。颜色主题是默认的。另外,不清楚怎么修改代码中的字体大小。这个一般不用改吧,目前的大小已经可以接收了。哈哈

  3. 2014年4月29日12:20 | #4

    代码文本写的挺好看的,你用的是什么主题,

  1. 2012年12月25日21:29 | #1
  2. 2013年4月6日15:25 | #2
  3. 2013年6月5日10:07 | #3
  4. 2013年9月8日18:19 | #4
  5. 2013年12月19日14:08 | #5
  6. 2014年5月19日10:52 | #6
  7. 2014年11月11日20:37 | #7
  8. 2016年5月22日12:16 | #8

无觅相关文章插件,快速提升流量