JavaScript挑战复杂报表——1总述
今天用自己写的库完成了一个40列填报报表的前后台调试,所花费的时间超过预期很多。遇到的坑有:ajax回调函数写错导致循环调用,没有考虑到java的request.getParameter()方法读入数据的长度限制,对json中的引号的转义处理理解不透彻,对同一数据项在JavaScript、Java、SQL三种语言中的数据类型转换失误,没有注意到前台数据集和数据库的几处结构差异。虽然最终完成了工作计划,但反复的调试与核对花费了太多的时间和精力。
又回到了那个“是否自己造轮子”的老问题。两年前刚参加工作时,我使用同事提供的Flex*Java*Oracle框架来快速上手,依靠这套框架我在较短的时间内完成了大量的简单报表编写工作,并积累了一些web编程的基础知识。
后来,用户对表格的功能提出了更细致的要求(多为根据不同的数据对表格的样式进行修改,比如数值超过100就设为红色之类),这些细化的要求并不是Flex和ActionScript所擅长的,在没有完善文档和例程的情况下,对每一个超出框架的小功能的修改都要花费极大的精力。再后来,随着Adobe放弃支持Flex转向Html5,Flex报表框架更是前途黯淡。
放弃Flex后,我又尝试了Ext.net控件、帆软报表设计器、润乾报表设计器等框架,但都不尽如人意。总结起来,这些框架的限制如下:
1、当用户提出的功能要求超过框架设计范围时,框架本身将无能为力,并且因为框架的复杂性应用开发者往往要花费更多的时间来实现功能;
2、应用开发者很难掌控框架的性能;
3、框架使用者在编程过程中积累的只是框架使用的经验,而不是真正的前端知识。
4、一旦框架背后的公司放弃对框架的支持,该框架的价值将急速降低。
综上,我开始尝试使用原生的JavaScript来编写报表绘制库,经过一段时间的努力,我自己的框架显出了雏形(JavaScript*Java*Oralcle)。在前台的报表绘制库里我实现了前台表格的样式控制、表元素点击相应、翻页、单元格嵌入复杂模块、锁定表头表列、动态列选择、点击表元素弹出窗口(div)、前台导入导出文本文件、前台Excel导出(IE only)等功能,初步摆脱了功能设计上的限制。
但随着客户需求的进一步升级,我的框架在处理“超大型填报表”时显得力不从心。根据经验,当报表的列数达到20列以上时,对单元格对象的管理、对前后台数据的同步(特别是对数据类型的同步)将超过实现复杂功能成为报表应用编写的主要矛盾。此时成熟框架的“设计器式”对象管理和前后台数据绑定技术就变得无比实用了。
现有的大部分成熟前端报表库都因为历史原因使用table、tr、td标签来进行表格绘制(我的也是),而浏览器会“自作聪明的”对这些标签进行超出开发者控制的样式调整,这不但使得报表绘制库的样式控制更加复杂,也使得单元格的精确控制和模块插入变得更难。在我看来,一个完美的报表绘制框架应该使用div标签绘制,用原生语言控制,并提供报表设计器和前后台数据绑定。
我并不准备自己投入这种框架的开发,一是时间和精力不足;二是我所在的单位在有多种选择时习惯通过投票来决定使用何种技术,在同事门都在用润乾画表的情况下,编写一个和润乾无关的框架必定不受欢迎。
现在看来,在一个成熟框架的基础上进行定制化修改,是一个兼顾了灵活性、工作效率和单位团结的好办法。
以下是表格绘制库att5的基本工程结构:

其中:
easyui的引入是为了方便的使用日历控件,如果不需要可以去掉;
testtab.css是主要的样式表文件;
test_01_base.html和test_01_base.js是基本示例;
DatePicker.js是网上找到的一个日历控件,功能比easyui弱,但更灵活;
webgl-utils.js是一个Google的3D动画库,主要用到其中的requestAnimFrame方法;
Events.js是事件处理库,主要来自Shelley Powers的《JavaScript经典实例》和网上搜集整理;
FileText.js是文件处理库是我参考网络教程编写的;
Table2.js是核心的表格绘制库(封装为att5),完全使用原生JavaScript编写;
View.js是样式处理库,根据书籍和网络搜集整理。
在示例js中少量使用了jQuery选择器简化编程,js库文件均为原生JavaScript。
下面是表格绘制库att5的基本使用示例(简单显示测试数据并实现数据集的文本保存):
/**
* Created by Administrator on 2016/5/6.
*/
//生成测试数据
function CreateTestData()
{
var count_row=200;//两百行数据
var count_col=10;//每行数据有十列
var arr_row=[]; for(var i=0;i<count_row;i++)
{
arr_row=[];
for(var j=0;j<count_col;j++)
{
arr_row.push("第"+(i+1)+"行第"+(j+1)+"列");
}
arr_user.push(arr_row);
}
DrawTable();
}
//在前台生成数据集并按数据集绘制表格
function DrawTable()
{
arr_user.unshift([100,100,100,100,100,100,100,100,100,100]);//10列,规定表列的最小宽度
var arr_DOM = [];
arr_DOM.push("str");
arr_DOM.push("str");
arr_DOM.push("str");
arr_DOM.push("str");
arr_DOM.push("str");
arr_DOM.push("str");
arr_DOM.push("str");
arr_DOM.push("str");
arr_DOM.push("str");
arr_DOM.push("str");
arr_user.unshift(arr_DOM);//向数据集中压入每一列的数据结构,这里全是简单字符类型
arr_user.unshift(["表头","表头","表头","表头","表头","表头","表头","表头","表头",
"表头"]);//压入表头
arr_user.unshift(dwmc+"最小功能测试表");//压入表名
//绘制表格并返回表格总页数
$('#t_page_span')[0].innerHTML=att5.ArrayToTable5("div_tab","tab_data",0,0,arr_user,30,pages);
$('#c_page_span')[0].innerHTML=pages+1;//当前所在页数
AdjustColor();//表格绘制完毕后根据需求对部分单元格样式进行微调
}
function AdjustColor()
{ } //用文本方式把数据集导出,兼容ie8-ie11,兼容chrome
function TextExport()
{
var str_data=JSON.stringify(arr_user);//为保持数据结构,压成json格式
DownloadText(MakeDateStr()+"数据集",str_data);
} //导入数据集,弹出一个用来选择文件的对话框
function ImportCol()
{
delete_div('div_ImportCol');//删除可能已经存在的对话框
Open_div("div_ssbup", "div_ImportCol", 640, 120, 80, 80, "", "", 0);//在指定位置打开一个div
$("#div_ImportCol")[0].innerHTML = $("#div_mod1")[0].innerHTML;//设置div的内容 //使得弹出框可以被拖拽
var div_ImportCol=$("#div_ImportCol")[0];
drag(div_ImportCol);
//把对弹出框内元素的操作与弹出框拖拽分离
var div_inmod_content=$("#div_ImportCol #btn_ImportCol")[0];
div_inmod_content.onmousedown=function()
{
var evt=evt||window.event;
cancelPropagation(evt);//阻断事件传播
}
var btn_close=$("#div_ImportCol .div_inmod_head button")[0];
btn_close.onmousedown=function()
{
var evt=evt||window.event;
cancelPropagation(evt);
}
}
//导入文本文件
function ImportCol2()
{
var evt=evt||window.event;
cancelPropagation(evt);
var obj=evt.currentTarget?evt.currentTarget:evt.srcElement;
UploadText(obj.value,evt,"ImportCol3(s)");
}
//根据导入的数据集绘制表格
function ImportCol3(str_json)
{
arr_user=JSON.parse(str_json);
delete_div('div_ImportCol');
$('#t_page_span')[0].innerHTML=att5.ArrayToTable5("div_tab","tab_data",0,0,arr_user,30,pages);
$('#c_page_span')[0].innerHTML=pages+1;
}
完整的基本示例和库文件下载:
https://github.com/ljzc002/att5
JavaScript挑战复杂报表——1总述的更多相关文章
- Java的多线程机制系列:(一)总述及基础概念
前言 这一系列多线程的文章,一方面是个人对Java现有的多线程机制的学习和记录,另一方面是希望能给不熟悉Java多线程机制.或有一定基础但理解还不够深的读者一个比较全面的介绍,旨在使读者对Java的多 ...
- 三国杀3v3心法——总述篇
昔日,独孤求败前辈精研剑法,将其中奥妙化为独孤九剑,破尽天下武功.其中开篇总诀式提纲挈领,从宏观的层面阐述剑道,是领悟后面八式的基石,而之后各式则深入微观,可各破一类具体的武功.笔者亦曾苦心研究三国杀 ...
- Web应用程序系统的多用户权限控制设计及实现-总述【1】
中大型的Web系统开发均需要权限的配置,基于多角色,多用户的操作权限管理是一个系统开发的基础.搭建好一套权限,用户,角色,页面一体的开发架构,可以用于后期业务的开发,同时也可用于不同业务的系统开发. ...
- Linux makefile教程之总述二[转]
Makefile 总述——————— 一.Makefile里有什么? Makefile里主要包含了五个东西:显式规则.隐晦规则.变量定义.文件指示和注释. 1.显式规则.显式规则说明了,如何生成一个或 ...
- Solr4.8.0源码分析(5)之查询流程分析总述
Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilt ...
- 很详细、很移动的Linux makefile教程:介绍,总述,书写规则,书写命令,使用变量,使用条件推断,使用函数,Make 的运行,隐含规则 使用make更新函数库文件 后序
很详细.很移动的Linux makefile 教程 内容如下: Makefile 介绍 Makefile 总述 书写规则 书写命令 使用变量 使用条件推断 使用函数 make 的运行 隐含规则 使用m ...
- STL特性总述——写在前面
所谓的容器,见名知意,容纳其他数据的"器具": 特点 1)支持泛型: 2)保存副本:本质上传入对象的拷贝. 3)内存托管 :构建对象于堆,无需人工干预,自动管理内存的生存周期. S ...
- [转] Makefile 基础 (2) —— Makefile 总述
该篇文章为转载,是对原作者系列文章的总汇加上标注. 支持原创,请移步陈浩大神博客:(最原始版本) http://blog.csdn.net/haoel/article/details/2886 我转自 ...
- 基于ASP.Net Core开发一套通用后台框架记录-(总述)
写在前面 本系列博客是本人在学习的过程中搭建学习的记录,如果对你有所帮助那再好不过.如果您有发现错误,请告知我,我会第一时间修改. 前期我不会公开源码,我想是一点点敲代码,不然复制.粘贴那就没意思了. ...
随机推荐
- 【Eclipse】 Alt+/ 代码提示问题解决方案
一般情况下alt+/有代码提示作用,还有代码提示的快捷代码也不是alt+/,因此要恢复代码提示用alt+/.需要做两件事. 在 Window - Preferences - General - Key ...
- (转)KeyDown、KeyUp、KeyPress区别
Windows窗体通过引发键盘事件来处理键盘输入以响应Windows消息,大多数Windows窗体应用程序都通过处理键盘事件来以独占方式处理键盘输入. 1.按键的类型 Windows窗体将键盘输入标 ...
- msnodesql的使用
msnodesql的安装 npm install msnodesql 使用msnodesql写的增删改查 var sql=require('msnodesql'); var conn_str= ...
- bzoj1222: [HNOI2001]产品加工--DP
DP神题orz dp[i]表示机器1工作i小时,机器2工作dp[i]小时 那么对于每个任务: 选1:dp[i]=dp[i-a]; 选2:dp[i]=dp[i]+b; 选1+2:dp[i]=dp[i-c ...
- bzoj2743: [HEOI2012]采花--离线树状数组+差分
题目大意:给定一个区间,查询子区间里出现次数不小于二的数的个数 此题想了好久没想出来,后来是在网上学习的一个方法 首先按查询区间的右端点进行排序,按右端点从小到大处理 假设pre[a[i]]是与a[i ...
- 微信APP支付Java后端回调处理
package com.gaoxiao.framework.controller.gaojia; import com.gaoxiao.framework.commonfiles.entity.Sta ...
- Bootstrap Chart组件使用分享
图表组件Chart.js是Bootstrap比较好用的组件之一,与一款收费的组件highchart类似,效果上来看免费与收费的产品相差还是有一点点的,不过功能上差不多能满足我们项目的需要.下面这段JS ...
- PowerDesigner V16.5 安装文件 及 破解文件
之前在网上找个假的,只能看,不能创建自己的DB; 或者 不能破解的,比较伤脑筋. 偶在这里提供一个 可长期使用的版本. PowerDesigner165_破解文件.rar 链接:http://p ...
- Xstream(对象和xml转换)
package com.vcredit.framework.utils; import java.io.Writer; import org.apache.commons.lang3.StringUt ...
- SQL Server 触发器(转)
触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程.触发器主要是通过事件进行触发被自动调用执行的.而存储过程可以通过存储过程的名称被调用. Ø 什么是触发器 触发器对表进行插入.更新.删 ...