前面一段时间写了一篇文章:
如何用easyui+JAVA 实现动态拼凑datagrid表格
这篇文章的话,效果是可以实现,但是经过我反复试验,还是存在一些问题的。
今天这篇文章就是向大家介绍下如何避免和解决这些问题。
问题如下:
这个TEMP值其实就是上面文章提到的z1,z2,z3,z4的值,也就是说,每次进行each循环,都会查出不同的值,并返回,但是事实并不是这样的
这个TEMP返回的是EACH循环以后的最后一次的值。
记住,EACH循环本身就是一个封闭的,不会循环一次返回一个值,而是让前面的值被后面的值覆盖掉了!,所以查出来的结果都一样了,怎么样避免这种情况的发生呢?
我先放出整个代码块,然后我们再一步一步分析并解决问题。
using("sable.easyui"); var gv=$("#dg");
var today=new Date(); //动态生成列
var dynamicCols=[];
var dynamicItems=[];
var dynamicItemsAfter=[];
var dynamicItemsEnd=[]; //设置时间
function GetDateStr(AddDayCount) {
var dd = new Date();
dd.setDate(dd.getDate()+AddDayCount);//获取AddDayCount天后的日期
var y = dd.getFullYear();
var m = dd.getMonth()+1;//获取当前月份的日期
var d = dd.getDate();
return y+"-"+m+"-"+d;
} //以开始时间为基准设置时间 function GetDateStrA(AddDayCount) { //得到开始时间 var dd = new Date($("#StartTime").datebox('getValue'));
dd.setDate(dd.getDate()+AddDayCount);//获取AddDayCount天后的日期
var y = dd.getFullYear();
var m = dd.getMonth()+1;//获取当前月份的日期
var d = dd.getDate();
return y+"-"+m+"-"+d;
} $(function(){
$("#StartTime").datebox('setValue',GetDateStr(-1));
$("#EndTime").datebox('setValue',GetDateStr(0)); //绑定空数据
gv.datagrid( "dataBind" ,
{
autoHeight : 46 ,
datas : [],
striped:true,
pagination : true,
autoRowHeight:false });
//绑定空列
gv.datagrid({
columns:[[
{title:'时间',width:150,sortable:true},
{title:'站点1',width:150,sortable:true},
{title:'站点2',width:150,sortable:true},
{title:'站点3',width:500,sortable:true},
]] }); }); //列元素(动态)
//序号
var stcd={
field: 'Stcd',
title: '序号',
// width: 150,
rowspan:3,
sortable:true
} //站名
var stnm={
field: 'Stnm',
title: '站名',
// width: 150,
rowspan:3,
sortable:true
} //平均值
var avg={
title:'平均值',
//width:500,
colspan:2
} //库水位
var rz={
title:'库水位',
//width:150 /*PS:动态列中不适宜固定宽度,其他同样的*/
} //库容
var rv={
title:'库容',
width:150
} //查询按钮
$("#btnSearch").click(function(){ //得到开始日期和结束日期之间的天数之差
var ipt1=$("#StartTime").datebox('getValue');
var ipt2=$("#EndTime").datebox('getValue'); var arr1 = ipt1.split("-");
var arr2 = ipt2.split("-"); var dt1 = new Date();
dt1.setFullYear(arr1[0]);
dt1.setMonth(arr1[1] - 1);
dt1.setDate(arr1[2]);
var dt2 = new Date();
dt2.setFullYear(arr2[0]);
dt2.setMonth(arr2[1] - 1);
dt2.setDate(arr2[2]);
var dif = dt2.getTime() - dt1.getTime();
var days = dif / (24 * 60 * 60 * 1000); //再次初始化,避免数组的堆积
dynamicCols=[];
dynamicItems=[];
dynamicItemsAfter=[];
dynamicItemsEnd=[]; //前部
dynamicItems.push(stcd);
dynamicItems.push(stnm); //查询条件数据
var datas={
"Stcd":$("#stnmCombo").combobox('getValue'),
"StartTime":$("#StartTime").datebox('getValue'),
"EndTime":$("#EndTime").datebox('getValue')
}
//查询具体的数据
formLoader.load("querydata",datas,function(s){ //空白SPAN
var blank={
title:' ',
colspan:days*2+4 //动态得到COLSPAN的跨度,根据天数 }
dynamicItems.push(blank); //动态载入库水位数据 //创建一个新的存储MAP中的键的东西(表头Field) -水位
var index=[];
$.each(s[0].DynamicList, function(i,option){
index.push(i); }); //创建一个新的存储MAP中的键的东西(表头Field) -流量
var indexQ=[];
$.each(s[0].DynamicListQ, function(i,option){
indexQ.push(i); }); //拼凑表头
$.each(s[0].DynamicList, function(i,option){ //详细数据
var k=0; //设定一个值,匹配Z0,Z1,Z2。。。。。 var d = new Date($("#StartTime").datebox('getValue'));
do{
//alert(i.substring(1));
d.setDate(d.getDate()+(parseInt(i.substring(1)))/2); //转换成INT类型的 var RealDate=d.getFullYear()+"-"+(d.getMonth()+1)+"-"+d.getDate(); //动态得到日期值 var details2={
title:RealDate,
// width:150,
colspan:2 } dynamicItemsAfter.push(details2);
k+=2;
break; //这里因为会执行i此结果 ,所以 BREAK掉
}while(days>k) }); //把水位和流量合并成一个对象
var extend=function(o,n,override){
for(var p in n)
{
//alert(n[p]); if(n.hasOwnProperty(p) && (!o.hasOwnProperty(p) || override))
{ o[p]=n[p];
} } };
extend(s[0].DynamicList,s[0].DynamicListQ); //表头排序
/*表头排序的作用是将2个不相干的MAP组合到一起,然后按照第二个数字的大小进行冒泡排序*/
var aa=Object.keys(s[0].DynamicList);
var bb=[]; // for(var j=0;j<aa.length;j++)
// {
// var temp;
//
// if(j+1==aa.length)
// {
// break;
// }
//
//// alert(aa[j]);
//// alert(aa[j+1]);
//
// if(Number(aa[j].substring(1))>Number(aa[j+1].substring(1)))
// {
//
// temp=aa[j];
// aa[j]=aa[j+1];
// aa[j+1]=temp;
// }
//
//
// } //进行排序,因为是从第二个字母开始比较大小的,所以截取字符串长度
aa.sort(function(a,b){return Number(a.substring(1))>Number(b.substring(1))?1:-1});
//alert(aa);
//alert(aa);
//alert(aa.sortable());
//再次PUSH表头列
var indexAll=[];
$.each(s[0].DynamicList, function(i,option){
indexAll.push(i);
}); //alert(aa);
//alert(Object.Keys());
var z=Object.keys(s[0].DynamicList);
var q=Object.keys(s[0].DynamicListQ); //这里的s指的是下标0,1,2,3,m指的是对应的z0,q1,z2,q3等等
$(aa).each(function(s,m){ for(var j=0;j<index.length;j++)
{
// if(j<z.length)
// {
if(m==index[j])
{
//alert(index[j]);
var mk=index[j]; //库水位
rz={
title:'水位',
field:"DynamicList"+mk, //切记,这里的field不能相同,每次循环都需要创建一个新的FIELD
formatter:function(value,row,index){
//alert(row);
//return value.z1; //因为这是一个对象DynamicList,所以返回对象的值
//alert(value); var temp=[]; var count=0;
var final;
$.each(row.DynamicList,function(i,option){ temp[i]=bibao(option); }); //alert(temp["z0"]());
return temp[mk]();
//return temp;
}
}
dynamicItemsEnd.push(rz);
}
if(m==indexQ[j])
{ var mk2=indexQ[j]; //流量(动态值)
rv={
title:'流量',
field:"DynamicListQ"+mk2,
formatter:function(value,row,index)
{
var temp2=[];
$.each(row.DynamicListQ,function(i,option){
//alert(option); temp2[i]=bibao(option); //闭包法则 });
//alert(temp2[mk2]());
return temp2[mk2]();
}
}
dynamicItemsEnd.push(rv);
} } }); //库水位(平均)
var rzAvg={
title:'水位',
field:"AvgRz"} //流量(平均)
var rvAvg={
title:'流量',
field:"AvgQ",
//width:500
formatter:function(value,row,index)
{
if(value=="NaN")
{
return "-";
}
else
{
return value;
}
}
} dynamicItemsAfter.push(avg);
dynamicItemsEnd.push(rzAvg);
dynamicItemsEnd.push(rvAvg); dynamicCols.push(dynamicItems);
dynamicCols.push(dynamicItemsAfter);
dynamicCols.push(dynamicItemsEnd); //绑定动态列
gv.datagrid({
columns:dynamicCols, }); //获取动态表头
var opts = $('#dg').datagrid('getColumnFields');
colName_=[]; //全局变量 var count=0.5;
var r = /^[-+]?\d*$/; //判断是否为整数 for(i=0;i<opts.length;i++)
{ var col = $('#dg').datagrid( "getColumnOption" , opts[i] ); var title=col.title; if(i>=2)
{
//奇数列必须和偶数列的值相同,也就是说水位和库容值相同。比如1月水位,1月库容,2月水位,2月库容。
//如果i的值为奇数的话,那么比如使奇数列的值和上一个偶数列的值相同,也就是减一。
//每次增量改为0.5,也就是2分之一,可以有效避免数字退后。
//因为是从0开始计算的,所以下面的并不是i-3和i-4而是i-2,i-3 //偶数列
if(r.test(count)==true)
{
if((i-2)%2==0)
{ title=col.title+"("+GetDateStrA(i-1-count)+")"; }
else if((i-2)%2!=0)
{
title=col.title+"("+GetDateStrA(i-2-count)+")"; }
}
//奇数列
else
{
if((i-2)%2==0)
{ title=col.title+"("+GetDateStrA(i-1-count-0.5)+")"; }
else if((i-2)%2!=0)
{
title=col.title+"("+GetDateStrA(i-2-count-0.5)+")"; } } count+=0.5;
//最后一列算作平均值,不参与计算
if(i==opts.length-2||i==opts.length-1)
{
title=col.title+"(平均值)";
} } colName_.push(title);
} gv.datagrid( "dataBind" ,
{
datas : s,
striped:true,
pagination : true,
pageSize:15 }); }); //重置大小,动态重置
if(days>11)
{
var realwidth=1700+125*(days-11)
gv.datagrid("resize",{width:realwidth});
}
else
{
gv.datagrid("resize",{width:1360});
} }); //导出excel
$("#export").click(function(){ var url= colName_;
location.href = context.RootPath + context.ControllerPath + "/exportexcel?StartTime="+$("#StartTime").datebox('getValue')+"&EndTime="+$("#EndTime").datebox('getValue')+"&Stcd="+$("#stnmCombo").combobox('getValue')+"&ColName="+encodeURI(encodeURI(url)); }); //得到测站编码
var dataCount=0;
formLoader.load("getstnm","",function(data){ data.unshift({Stnm : "全部" , Stcd : "" });
$("#stnmCombo").combobox({
data:data,
valueField:"Stcd",
textField:"Stnm",
editable:false,
//panelHeight:"auto", onLoadSuccess:function()
{
//alert('1');
//alert(data[0].Stcd);
$("#stnmCombo").combobox('setValue',data[0].Stcd);
dataCount=data.length; },
onShowPanel:function()
{
if(dataCount.length>10)
{
$(this).combobox('panel').height(251); } }
});
}); //闭包效应
function bibao(a){
return function (){
return a;
}
}
riverdayreport.js
上面的是整个JS代码块,大家看得可能有点头晕,我们下面就来一步一步分析。
先放张效果图吧。
上面的是正确的结果,每一天的值都是不同的。
我们在解决这个值的显示问题的时候还要明白一个隐含的问题:每一天不止有水位,还有库容。
水位和库容在Json对象里面都是按照z0,z1,z2...q0,q1,q2这样的键值对的形式存在的,其中z开头的为水位,q开头的为库容。
我这里拿的是另一个JS跟你们讲解的,其实都一样啦,大家明白原理就行了。
//创建一个新的存储MAP中的键的东西(表头Field) -水位
var index=[];
$.each(s[0].DynamicList, function(i,option){
index.push(i); }); //创建一个新的存储MAP中的键的东西(表头Field) -流量
var indexQ=[];
$.each(s[0].DynamicListQ, function(i,option){
indexQ.push(i); });
上面的代码其实是得到水位或者流量的index,即键值对中的键,然后把这些键存到2个数组里面去。
下面的代码是单独进行表头的拼接,唯一需要注意的是,一个日期跨度为2列,包括了水位和库容。
//拼凑表头
$.each(s[0].DynamicList, function(i,option){ //详细数据
var k=0; //设定一个值,匹配Z0,Z1,Z2。。。。。 var d = new Date($("#StartTime").datebox('getValue'));
do{
//alert(i.substring(1));
d.setDate(d.getDate()+(parseInt(i.substring(1)))/2); //转换成INT类型的 var RealDate=d.getFullYear()+"-"+(d.getMonth()+1)+"-"+d.getDate(); //动态得到日期值 var details2={
title:RealDate,
// width:150,
colspan:2 } dynamicItemsAfter.push(details2);
k+=2;
break; //这里因为会执行i此结果 ,所以 BREAK掉
}while(days>k) });
因为后面要循环PUSH,把水位或者流量给PUSH到数组里面去,然后显示动态列,所以,这里我们合并一下2个动态列
//把水位和流量合并成一个对象
var extend=function(o,n,override){
for(var p in n)
{
//alert(n[p]); if(n.hasOwnProperty(p) && (!o.hasOwnProperty(p) || override))
{ o[p]=n[p];
} } };
extend(s[0].DynamicList,s[0].DynamicListQ);
这里用到了原生态的EXTEND方法去合并。
现在就变成了z0~zn,q0~qn
这显然不是我们想要的结果,因为正确的顺序其实是z0,q0,z1,q1,那么这里我们就需要进行排序
aa.sort(function(a,b){return Number(a.substring(1))>Number(b.substring(1))?1:-1});
排序完了,一半的工作就进行完了。
这里还用到了闭包,就是在EACH外面访问EACH里面的返回值。
具体代码如下:
//闭包效应
function bibao(a){
return function (){
return a;
}
}
既然排序已经完成了,我们就可以一路下来放心的EACH了。
下面的代码用到了另一种EACH,其中参数m为z0,q0,z1,q1这些键。
唯一需要注意的是,每次的FIELD都是不同的,因为FIELD有唯一性。
在每次formatter里面的值是从row.对象 里面取出来的哦,这点要注意。
//这里的s指的是下标0,1,2,3,m指的是对应的z0,q1,z2,q3等等
$(aa).each(function(s,m){ for(var j=0;j<index.length;j++)
{
// if(j<z.length)
// {
if(m==index[j])
{
//alert(index[j]);
var mk=index[j]; //库水位
rz={
title:'水位',
field:"DynamicList"+mk, //切记,这里的field不能相同,每次循环都需要创建一个新的FIELD
formatter:function(value,row,index){
//alert(row);
//return value.z1; //因为这是一个对象DynamicList,所以返回对象的值
//alert(value); var temp=[]; var count=0;
var final;
$.each(row.DynamicList,function(i,option){ temp[i]=bibao(option); }); //alert(temp["z0"]());
return temp[mk]();
//return temp;
}
}
dynamicItemsEnd.push(rz);
}
if(m==indexQ[j])
{ var mk2=indexQ[j]; //流量(动态值)
rv={
title:'流量',
field:"DynamicListQ"+mk2,
formatter:function(value,row,index)
{
var temp2=[];
$.each(row.DynamicListQ,function(i,option){
//alert(option); temp2[i]=bibao(option); //闭包法则 });
//alert(temp2[mk2]());
return temp2[mk2]();
}
}
dynamicItemsEnd.push(rv);
} } });
下面再个大家放一个小小的福利,就是如何做多级菜单,我这里只做到了3级,这个多级菜单的话,其实大家并不陌生,关键是我这个多级菜单是专门为公司做的,
也就是说有些方法在网上很难找到答案。
废话不多,开搞。
$.each(model.NavigateData,function(index,value)
{
if( $.trim(value.Text) =="浏阳山洪灾害预警系统")
{
mainid = value.Value;
$('.main_head_left').css('background-image','url( ../interface/view/default/core/public/skin/default/images/core_index_main/logo.jpg)');
$('.logo2').css('left','660px');
menulist.push(mainid);
}
});
//一级菜单
$.each(model.NavigateData,function(index,value)
{
if( $.trim(value.ParentValue) == mainid)
{
var vl = value.Value;
//mainmenu = mainmenu + "<td><a href='#' class='mymenu' id='menu"+k+"' name='"+value.Value+"'>"+value.Text+"</a> </td>";
mainmenu = mainmenu + "<li><a href='#' id='menu"+k+"' name='"+value.Value+"'>"+value.Text+"</a></li>";
concatDiv(vl,k);
k++;
menulist.push(vl);
}
});
//添加主菜单
$('#tbmenu').append(mainmenu);
//二级菜单
function concatDiv(vl,k)
{
var count=0;
var divStr = "<div id='mm"+k+"' style='width:140px;'>";
$.each(model.NavigateData,function(index,value)
{
var vl2=value.Value;
if(value.ParentValue == vl)
{
//alert(vl);
//menulist.push(value.Value);
var link = value.Link;
divStr = divStr + "<div id='"+link+"' name='"+value.Value+"' onclick='setUrl(this);'>"+"<span>"+value.Text+"</span>"; //添加三级菜单,原理就是先找出对应的二级菜单,然后再进行遍历
//divStr+="<div>";
//tempMenu(value.Value,k);
//把子菜单PUSH到数组里去
//SAME数组用来存放有三级菜单父级ID的数组。
var s=[];
var same=[];
$.each(model.NavigateData,function(index,value){
var vl=value.Value;
var vlparent=value.ParentValue;
var link =value.Link; if(vlparent==vl2)
{
//alert("parent:"+vlparent+",vl2:"+vl2); //alert(value.Value); var div=$("div[name='"+vlparent+"'] .menu-text");
var divSub=$("div[name='"+vl+"']");
//divStr = divStr + "<div id='"+link+"' name='"+value.Value+"' onclick='setUrl(this);'>"+"<span>"+value.Text+"</div>";
s.push("<div id='"+link+"' name='"+value.Value+"' onclick='setUrl(this);'>"+"<span>"+value.Text+"</div>");
same.push(vlparent);
//divStr+="<div><div>1</div><div>2</div></div>";
//divStr+=divStrSub; } }); //去除相同的元素 function unique(array) {
var ret = [], record = {},it,tmp,obj = "__object__", bak = [],i,len;
var type ={
"number": function(n) { return "__number__" + n; },
"string": function(n) { return "__string__" + n; },
"boolean": function(n) { return "__boolean__" + n; },
"undefined": function(n) { return "__undefined__"; },
"object": function(n) {
return n === null ? "__null__" : obj in n ? n[obj] : ( n[obj] = obj + bak.push(n) );
}
};
for (i = 0, len = array.length; i < len; i++) {
it = array[i]; tmp = type[typeof it](it);
if (!(tmp in record)) { ret.push(it); record[tmp] = true; }
}
for (i = 0, len = bak.length; i < len; delete bak[i++][obj]) { }
return ret;
};
var uniq=unique(same); //判断是否为3级菜单的元素
$.each(model.NavigateData,function(index,value){
var vl=value.Value;
var vlparent=value.ParentValue;
var link =value.Link; if(vlparent==uniq)
{
divStr+="<div>";
divStr+=s.join(''); //把数组里的数据全部加进来
divStr+="</div>"; } }); //alert(s);
//divStr+="</div>"; //
// if(value.Value=="b15fa5ba-5a73-4792-a65a-5bcf2e8a20ec")
// {
// divStr+="<div><div>1</div><div>2</div></div>";
// } divStr+="</div>"; //tempMenu(value.Value);
} });
divStr = divStr+"</div>";
$('#main').append(divStr);
} //添加菜单项
for(var i=0;i<k;i++)
{
$('#menu'+i).menubutton({menu:'#mm'+i}); }
多级带单.js
大家又头晕了吧?容我慢慢道来,
这种多级菜单并不是通过ul li来实现的,而是通过div来实现的。
easyui有一个方法叫做menubutton,可以添加二级菜单
//添加菜单项
for(var i=0;i<k;i++)
{
$('#menu'+i).menubutton({menu:'#mm'+i}); }
其中的model.NavigateData里面存储的是如下JSON
大家看到了吧?就是所有的菜单项的数据,我们需要的工作是提取有效的东西从里面。
具体怎么实现3级菜单上面都写了,就是在下图箭头所指的地方字符串拼接DIV
但是这里有一个难点,就是每次拼接出来的都是一个一个的整体,而我每个三级菜单其实是包含在一个大的DIV下面的。如下图
大家看到了吧,测试菜单2,3,4其实是在一个大的DIV里面的,而这个大的DIV只循环了一次,小的内容迭代了3次,这个如何实现的呢?
上面代码写了注释,我简单的说一下,其实很简单,就是把里面的三项的DIV都迭代出来放到数组里面去,然后再把他们的父亲节点的ID放入数组,由于迭代次数有多次,所以数组里有多个一样的东西,所以我们需要去掉相同的,然后再迭代判断父亲ID是否等于数组里面的ID,如果相等的话,把里面的数据拼接字符串,是不是很简单呢?
就说到这里了,最后:
祝大家中秋节快乐!!!