今天用自己写的库完成了一个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总述的更多相关文章

  1. Java的多线程机制系列:(一)总述及基础概念

    前言 这一系列多线程的文章,一方面是个人对Java现有的多线程机制的学习和记录,另一方面是希望能给不熟悉Java多线程机制.或有一定基础但理解还不够深的读者一个比较全面的介绍,旨在使读者对Java的多 ...

  2. 三国杀3v3心法——总述篇

    昔日,独孤求败前辈精研剑法,将其中奥妙化为独孤九剑,破尽天下武功.其中开篇总诀式提纲挈领,从宏观的层面阐述剑道,是领悟后面八式的基石,而之后各式则深入微观,可各破一类具体的武功.笔者亦曾苦心研究三国杀 ...

  3. Web应用程序系统的多用户权限控制设计及实现-总述【1】

    中大型的Web系统开发均需要权限的配置,基于多角色,多用户的操作权限管理是一个系统开发的基础.搭建好一套权限,用户,角色,页面一体的开发架构,可以用于后期业务的开发,同时也可用于不同业务的系统开发. ...

  4. Linux makefile教程之总述二[转]

    Makefile 总述——————— 一.Makefile里有什么? Makefile里主要包含了五个东西:显式规则.隐晦规则.变量定义.文件指示和注释. 1.显式规则.显式规则说明了,如何生成一个或 ...

  5. Solr4.8.0源码分析(5)之查询流程分析总述

    Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilt ...

  6. 很详细、很移动的Linux makefile教程:介绍,总述,书写规则,书写命令,使用变量,使用条件推断,使用函数,Make 的运行,隐含规则 使用make更新函数库文件 后序

    很详细.很移动的Linux makefile 教程 内容如下: Makefile 介绍 Makefile 总述 书写规则 书写命令 使用变量 使用条件推断 使用函数 make 的运行 隐含规则 使用m ...

  7. STL特性总述——写在前面

    所谓的容器,见名知意,容纳其他数据的"器具": 特点 1)支持泛型: 2)保存副本:本质上传入对象的拷贝. 3)内存托管 :构建对象于堆,无需人工干预,自动管理内存的生存周期. S ...

  8. [转] Makefile 基础 (2) —— Makefile 总述

    该篇文章为转载,是对原作者系列文章的总汇加上标注. 支持原创,请移步陈浩大神博客:(最原始版本) http://blog.csdn.net/haoel/article/details/2886 我转自 ...

  9. 基于ASP.Net Core开发一套通用后台框架记录-(总述)

    写在前面 本系列博客是本人在学习的过程中搭建学习的记录,如果对你有所帮助那再好不过.如果您有发现错误,请告知我,我会第一时间修改. 前期我不会公开源码,我想是一点点敲代码,不然复制.粘贴那就没意思了. ...

随机推荐

  1. Codeforces #Round 376 F 题解

    F. Video Cards time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  2. BZOJ2844: albus就是要第一个出场

    Description 已知一个长度为n的正整数序列A(下标从1开始), 令 S = { x | 1 <= x <= n }, S 的幂集2^S定义为S 所有子集构成的集合. 定义映射 f ...

  3. android 百度地图开发

    package sposition.webjoy.net.sendposition; import android.os.Bundle; import android.support.design.w ...

  4. 如何在WORD2010中取消自动编号?

    如何在WORD2010中取消自动编号? 使用WORD2010有一个很大的问题就是WORD2010的自动编号问题,WORD2010的自动编号是符合外国人的写作习惯的,对中国人来说不适用. WORD201 ...

  5. [LintCode] Longest Substring Without Repeating Characters

    Given a string, find the length of the longest substring without repeating characters. Have you met ...

  6. [LintCode] Evaluate Reverse Polish Notation 计算逆波兰表达式

    Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, ...

  7. struts2中用xml配置文件去验证填写信息

    xml名字是这样的 actionName-validation.xml 每个action 对应一个xml文件 xml文件和action放在同一个包下 后台验证用户输入是否符合格式要求,不符合,提交后返 ...

  8. div居中

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. css 实现三角形的原理

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  10. 关于WPF中ItemsControl系列控件中Item不能继承父级的DataContext的解决办法

    WPF中所有的集合类控件,子项都不能继承父级的DataContext,需要手动将绑定的数据源指向到父级控件才可以. <DataGridTemplateColumn Header="操作 ...