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

生病的JavaScript代码

2012年9月25日 发表评论 阅读评论 1,211 人阅读    

  部门项目中,有一个导出功能。业务逻辑如下:根据数据的总记录数和每页大小,分批导出成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 
022function 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 
042PagingDownloader.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行报错。不过奇怪的是,如果这里执行如下的隐藏代码不会报错!!

  想来很久,不知道这个问题是怎么回事,也不知道如何解决。实在没辙,只好发出来,希望擅长的朋友帮忙解决一下。谢谢!!



作 者: D瓜哥,https://www.diguage.com/
原文链接:https://wordpress.diguage.com/archives/52.html
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。

  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