easyui中最新版本的TreeGrid同步树形表格、同步加异步树形表格、树形表格分页且异步查看子节点

  • Post author:
  • Post category:其他



最近做一个项目,项目中开始使用的TreeTable的一个纯js插件。也许是对这个封装的js不熟悉,不管怎么调试,出来的效果总是不太理想。没得办法,最后想起来easyUI对树形表格的展示效果还不错。


于是就根据easyUI官方最新的Demo做了下面的案例:





上面依次是TreeGrid同步加异步请求接口且数据未分页、同步加异步请求接口数据分页、同步请求接口未分页。


为啥要分上面三种呢?因为上面三种方式,请求接口、返回数据,以及携带的参数都不一样。



一、

同步请求接口未分页







后台接口对应的Model:







import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * *生成Easyui treeGrid的方法
 */
public class BimPlanComponentTreeGrid implements Serializable{

	private static final long serialVersionUID = 1L;
	
	private String id;
	private String planName;
	private Date planStartTime;
	private Date planEndTime;
	private Integer planTimeLimit;
	private String planTimeLimitUnit;
	private Double planPercentDone;
	private Integer planPriority;
	private String planParentId;
	private Integer planIndex;
	private String planResource;
	private String planRemark;
	private String planFileId;
	private String planState;
	private String state="open";
	private List<BimPlanComponentTreeGrid> children=new ArrayList<BimPlanComponentTreeGrid>();
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPlanName() {
		return planName;
	}
	public void setPlanName(String planName) {
		this.planName = planName;
	}
	public Date getPlanStartTime() {
		return planStartTime;
	}
	public void setPlanStartTime(Date planStartTime) {
		this.planStartTime = planStartTime;
	}
	public Date getPlanEndTime() {
		return planEndTime;
	}
	public void setPlanEndTime(Date planEndTime) {
		this.planEndTime = planEndTime;
	}
	public Integer getPlanTimeLimit() {
		return planTimeLimit;
	}
	public void setPlanTimeLimit(Integer planTimeLimit) {
		this.planTimeLimit = planTimeLimit;
	}
	public String getPlanTimeLimitUnit() {
		return planTimeLimitUnit;
	}
	public void setPlanTimeLimitUnit(String planTimeLimitUnit) {
		this.planTimeLimitUnit = planTimeLimitUnit;
	}
	public Double getPlanPercentDone() {
		return planPercentDone;
	}
	public void setPlanPercentDone(Double planPercentDone) {
		this.planPercentDone = planPercentDone;
	}
	public Integer getPlanPriority() {
		return planPriority;
	}
	public void setPlanPriority(Integer planPriority) {
		this.planPriority = planPriority;
	}
	public String getPlanParentId() {
		return planParentId;
	}
	public void setPlanParentId(String planParentId) {
		this.planParentId = planParentId;
	}
	public Integer getPlanIndex() {
		return planIndex;
	}
	public void setPlanIndex(Integer planIndex) {
		this.planIndex = planIndex;
	}
	public String getPlanResource() {
		return planResource;
	}
	public void setPlanResource(String planResource) {
		this.planResource = planResource;
	}
	public String getPlanRemark() {
		return planRemark;
	}
	public void setPlanRemark(String planRemark) {
		this.planRemark = planRemark;
	}
	public String getPlanFileId() {
		return planFileId;
	}
	public void setPlanFileId(String planFileId) {
		this.planFileId = planFileId;
	}
	public String getPlanState() {
		return planState;
	}
	public void setPlanState(String planState) {
		this.planState = planState;
	}
	public List<BimPlanComponentTreeGrid> getChildren() {
		return children;
	}
	public void setChildren(List<BimPlanComponentTreeGrid> children) {
		this.children = children;
	}
	public String getState() {
		return state;
	}
	public void setState(String state) {
		this.state = state;
	}
}

特别注意的是:实体类中必须包含state、children这两个属性。其中state=”closed”时表示此时的节点是叶级节点,即它是有子级节点;当state=”open”时表示此时的节点是子级节点,他没有子级节点。children这个属性是当前实体类集合。所以这里首先就想到需要使用到递归。




递归数组:







import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.mss.shtoone.bim.model.BimPlanComponentTreeGrid;

public class BimPlanComponentTreeGridList{
	
	List<BimPlanComponentTreeGrid> returnList = new ArrayList<BimPlanComponentTreeGrid>();
	
	/**
	 * 根据父节点的ID获取所有子节点
	 * @param list 分类表
	 * @param typeId 传入的父节点ID
	 * @return String
	 */
	public List<BimPlanComponentTreeGrid> getChildTreeObjects(List<BimPlanComponentTreeGrid> list,String praentId) {
		List<BimPlanComponentTreeGrid> returnList = new ArrayList<BimPlanComponentTreeGrid>();
		for (Iterator<BimPlanComponentTreeGrid> iterator = list.iterator(); iterator.hasNext();) {
			BimPlanComponentTreeGrid t = (BimPlanComponentTreeGrid) iterator.next();
			// 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
			if (t.getPlanParentId()==praentId) {
				recursionFn(list, t);
				returnList.add(t);
			}
		}
		return returnList;
	}
	
	/**
	 * 递归列表
	 * @param list
	 * @param TreeObject
	 */
	private void  recursionFn(List<BimPlanComponentTreeGrid> list, BimPlanComponentTreeGrid t) {
		List<BimPlanComponentTreeGrid> childList = getChildList(list, t);// 得到子节点列表
		t.setChildren(childList);
		if(childList.size()>0){
			t.setState("closed");
		}else{
			t.setState("open");
		}
		for (BimPlanComponentTreeGrid tChild : childList) {
			if (hasChild(list, tChild)) {// 判断是否有子节点
				//returnList.add(TreeObject);
				Iterator<BimPlanComponentTreeGrid> it = childList.iterator();
				while (it.hasNext()) {
					BimPlanComponentTreeGrid n = (BimPlanComponentTreeGrid) it.next();
					recursionFn(list, n);
				}
			}
		}
	}
	
	// 得到子节点列表
	private List<BimPlanComponentTreeGrid> getChildList(List<BimPlanComponentTreeGrid> list, BimPlanComponentTreeGrid t) {
		List<BimPlanComponentTreeGrid> tlist = new ArrayList<BimPlanComponentTreeGrid>();
		Iterator<BimPlanComponentTreeGrid> it = list.iterator();
		while (it.hasNext()) {
			BimPlanComponentTreeGrid n = (BimPlanComponentTreeGrid) it.next();
			if (n.getPlanParentId()!=null ) {
				if(n.getPlanParentId().equals(t.getId())){
					tlist.add(n);
				}
			}
		}
		return tlist;
	} 
	
     

	// 判断是否有子节点
	private boolean hasChild(List<BimPlanComponentTreeGrid> list, BimPlanComponentTreeGrid t) {
		return getChildList(list, t).size() > 0 ? true : false;
	}
	
	// 本地模拟数据测试
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		List<BimPlanComponentTreeGrid> TreeObjectList = new ArrayList<BimPlanComponentTreeGrid>();
		
		BimPlanComponentTreeGridList mt = new BimPlanComponentTreeGridList();
		List<BimPlanComponentTreeGrid> ns=mt.getChildTreeObjects(TreeObjectList,null);
		for (BimPlanComponentTreeGrid m : ns) {
			System.out.println(m.getPlanName());
			System.out.println(m.getChildren());
		}
		long end = System.currentTimeMillis();
		System.out.println("用时:" + (end - start) + "ms");
	}
}

后台通过ssh取出来的集合,通过




new BimPlanComponentTreeGridList().getChildTreeObjects(list,null);  //list为从后台取出来的数据集。(这里是取出所有的数据,无论子父关系,全都交给treeGrid)





前段js展示:


<div class="easyui-layout" fit="true" id="treeGrid" style="height:500px;">
    <table id="treeGridTableDynamic" fit="true" class="easyui-treegrid" ></table>
</div>
---------------------------
$("#treeGridTable").treegrid({
               animate:true,
               idField: 'id',
               treeField:"planName",
               title:"同步[未分页]",
               nowrap: false,
               animate: true,
               method: "GET",
               iconCls: 'icon-save',
               rownumbers: true,
               collapsible: true,
               loadMsg: "数据加载中,请稍后...",
               fitColumns: true,
               fit:true,
               url: url,
               lines: true,   //加树形条
               collapsible:true,//是否可折叠
               showFooter:false,//是否使用页脚
               columns: [[
                   { field:"id", title: "id", hidden: true },
                   { field:"xx", title: "项目名称", width: 200 },
                   { field:"xx", title: "开始时间", align: "center",formatter:dataFormat.formatShort },
                   { field:"xx", title: "终止时间", align: "center",formatter:dataFormat.formatShort }
               ]],
               onBeforeLoad: function(row,param){

               },
               onAfterEdit:function(row,changes){
                   //alert(row.xx);
               },
               onBeforeExpand: function(row){
                   //alert(row.xx);
               }
           });

以上便完成了treeGrid的同步表格的数据展示,结果发现点击第一级请求第二节点时,浏览器崩了,原因是数据量比较多,所以就有了以下的考虑。

同步加载树形结构的第一级,当点击树形表格数据的文件图标时,异步获取他的子级数据。
二、同步加异步请求接口未分页
$("#treeGridTableDynamic").treegrid({
                animate:true,
                idField: 'id',
                treeField:"planName",
                title:"同步加异步[未分页]",
                nowrap: false,
                animate: true,
                method: "GET",
                iconCls: 'icon-save',
                rownumbers: true,
                collapsible: true,
                loadMsg: "数据加载中,请稍后...",
                fitColumns: true,
                fit:true,
                url: url,
                lines: true,   //加树形条
                collapsible:true,//是否可折叠
                showFooter:false,//是否使用页脚
                checkbox: true,
                columns: [[
                    { field:"id", title: "id", hidden: true },
                    { field:"planName", title: "项目名称", width: 200 },
                    { field:"planStartTime", title: "开始时间", align: "center",formatter:dataFormat.formatShort },
                    { field:"planEndTime", title: "终止时间", align: "center",formatter:dataFormat.formatShort }
                ]],
                onBeforeLoad: function(row,param){
                    if (!row) {	// load top level rows
                        param.id = 0;	// set id=0, indicate to load new page rows
                    }else{
                        //这里进行异步请求
                        paramsModel.param1="";
                        paramsModel.param2="";
                        paramsModel.param3="";
                        paramsModel.param4="";
                        paramsModel.param5="";
                        paramsModel.param6="";
                        paramsModel.param7="";
                        paramsModel.param8="";
                        paramsModel.param9=row.id;
                        paramsModel.param10="";
                        paramsModel.page=1;
                        paramsModel.rows=10;
                        var requestNew = JSON.stringify(paramsModel);
                        requestNew = escape(encodeURIComponent(requestNew));  //处理中文乱码之类
                        $(this).treegrid("options").url =APIURL+"rest/getConstructionPlanTreeGridDynamic/"+requestNew+"/"+Key+".json";
                    }
                },
                onAfterEdit:function(row,changes){
                    //alert(row.planName);
                },
                onBeforeExpand: function(row){
                    //alert(row.planName);
                }
            })

此时 onBeforeLoad方法中row,在首次加载树形表格时,我们给他的一个参数=0,所以后台必然有一个当参数=0的时候请求他最高一级节点,即父节点,我们

父节点的parentid=null。而第二次当我们点击树形表格数据的文件图标时,我们后台把父节点的id==parentid作为查询条件返回,即可。
StringBuffer sql=new StringBuffer();
		List<BimPlanComponent> planFileList=new ArrayList<BimPlanComponent>();
		if(StringUtil.isNotEmpty(paramsModel.getParam9())){
			if(paramsModel.getParam9().equalsIgnoreCase("0")){
				sql.append("select a.id,planName,planStartTime,planEndTime,planTimeLimit,planTimeLimitUnit,planPercentDone,planPriority,planParentId,planIndex,planResource,planRemark,planFileId,planState ");
				sql.append("from BIM_ConstructionPlan as a inner join BIM_ConstructionPlanFile as b on a.planFileId=b.id ");
				sql.append(" inner join t_s_depart as c on b.departId=c.id where 1=1 and a.planParentId is NULL ");
				sql.append(sqlWhere.toString());
				List<Object[]> list=findListbySql(sql.toString());
				if(list.size()>0){
					for(int i=0;i<list.size();i++){
						Object[] obj=list.get(i);
						BimPlanComponent plan=new BimPlanComponent();
						plan.setId(String.valueOf(obj[0]));
						plan.setPlanName(StringUtil.isEmptyObject(obj[1], ""));
						plan.setPlanStartTime(GetDate.StrConvertDateShort(StringUtil.isEmptyObject(obj[2],"")));
						plan.setPlanEndTime(GetDate.StrConvertDateShort(StringUtil.isEmptyObject(obj[3],"")));
						plan.setPlanTimeLimit(Integer.parseInt(StringUtil.isEmptyObject(obj[4],null)));
						plan.setPlanTimeLimitUnit(StringUtil.isEmptyObject(obj[5],null));
						plan.setPlanPercentDone(Double.parseDouble(StringUtil.isEmptyObject(obj[6], null)));
						plan.setPlanPriority(Integer.parseInt(StringUtil.isEmptyObject(obj[7],null)));
						plan.setPlanParentId(StringUtil.isEmptyObject(obj[8],null));
						plan.setPlanIndex(Integer.parseInt(StringUtil.isEmptyObject(obj[9],null)));
						plan.setPlanResource(StringUtil.isEmptyObject(obj[10],null));
						plan.setPlanRemark(StringUtil.isEmptyObject(obj[11],null));
						plan.setPlanFileId(StringUtil.isEmptyObject(obj[12],null));
						plan.setPlanState(StringUtil.isEmptyObject(obj[13],null));
						Long longCount=getCountForJdbc("select count(*) from BIM_ConstructionPlan where planParentId='"+plan.getId()+"'");
						if(longCount>0){
							plan.setState("closed");
						}else{
							plan.setState("open");
						}
						planFileList.add(plan);
					}
				}
			}else{
				//清空sql
				sql.setLength(0);
				sql.append("select a.id,planName,planStartTime,planEndTime,planTimeLimit,planTimeLimitUnit,planPercentDone,planPriority,planParentId,planIndex,planResource,planRemark,planFileId,planState ");
				sql.append("from BIM_ConstructionPlan as a inner join BIM_ConstructionPlanFile as b on a.planFileId=b.id ");
				sql.append(" inner join t_s_depart as c on b.departId=c.id where 1=1 and a.planParentId='"+paramsModel.getParam9()+"' ");
				sql.append(sqlWhere.toString());
				List<Object[]> list=findListbySql(sql.toString());
				if(list.size()>0){
					for(int i=0;i<list.size();i++){
						Object[] obj=list.get(i);
						BimPlanComponent plan=new BimPlanComponent();
						plan.setId(String.valueOf(obj[0]));
						plan.setPlanName(StringUtil.isEmptyObject(obj[1], ""));
						plan.setPlanStartTime(GetDate.StrConvertDateShort(StringUtil.isEmptyObject(obj[2],"")));
						plan.setPlanEndTime(GetDate.StrConvertDateShort(StringUtil.isEmptyObject(obj[3],"")));
						plan.setPlanTimeLimit(Integer.parseInt(StringUtil.isEmptyObject(obj[4],null)));
						plan.setPlanTimeLimitUnit(StringUtil.isEmptyObject(obj[5],null));
						plan.setPlanPercentDone(Double.parseDouble(StringUtil.isEmptyObject(obj[6], null)));
						plan.setPlanPriority(Integer.parseInt(StringUtil.isEmptyObject(obj[7],null)));
						plan.setPlanParentId(StringUtil.isEmptyObject(obj[8],null));
						plan.setPlanIndex(Integer.parseInt(StringUtil.isEmptyObject(obj[9],null)));
						plan.setPlanResource(StringUtil.isEmptyObject(obj[10],null));
						plan.setPlanRemark(StringUtil.isEmptyObject(obj[11],null));
						plan.setPlanFileId(StringUtil.isEmptyObject(obj[12],null));
						plan.setPlanState(StringUtil.isEmptyObject(obj[13],null));
						Long longCount=getCountForJdbc("select count(*) from BIM_ConstructionPlan where planParentId='"+plan.getId()+"'");
						if(longCount>0){
							plan.setState("closed");
						}else{
							plan.setState("open");
						}
						planFileList.add(plan);
					}
				}
			}
		}
		return planFileList;

     特别注意每一级节点都要通过数据来判断他的state属性

第一种方式和第二种方式最终返回都是List集合,然后通过GSON格式化成json数据,丢给treeGrid处理。

 虽然第二种方式解决了浏览器被程序卡死的情况。并且每次点击父节点请求子节点时,都只是请求当前父节点的
下一级。但是如果父节点的数据很多的话,我们就要一直拉动滚动条,这样肯定用户使用不方便。
   怎么办呢?于是分页
三、同步加异步请求接口分页

首先通过第二个,我们知道了分页的对象是什么?

       对,是父节点,也就是parent=null的那一级。而父节点下面的所有子节点都不进行分页
所以我们前端,只需要加上分页属性即可
$("#treeGridPageTable").treegrid({
               animate:true,
               idField: 'id',
               treeField:"planName",
               title:"测试TreeGrid[分页]",
               nowrap: true,
               animate: true,
               method: "GET",
               iconCls: 'icon-save',
               collapsible: true,
               loadMsg: "数据加载中,请稍后...",
               rownumbers: true,
               fitColumns: true,
               fit:true,
               url: url,
               lines: true,   //加树形条
               pagination: true,
               pageSize: 5,
               pageList: [5,20,30],
               collapsible:false,//是否可折叠
               showFooter:false,//是否使用页脚
               striped: true,
               collapsible:true,//是否可折叠
               columns: [[
                   { field:"id", title: "id", hidden: true },
                   { field:"planName", title: "项目名称", width: 200 },
                   { field:"planStartTime", title: "开始时间", align: "center",formatter:dataFormat.formatShort },
                   { field:"planEndTime", title: "终止时间", align: "center",formatter:dataFormat.formatShort }
               ]],
               onBeforeLoad: function(row,param){
                   if (!row) {	// load top level rows
                       param.id = 0;	// set id=0, indicate to load new page rows
                   }else{
                       //这里进行异步请求
                       paramsModel.param1="";
                       paramsModel.param2="";
                       paramsModel.param3="";
                       paramsModel.param4="";
                       paramsModel.param5="";
                       paramsModel.param6="";
                       paramsModel.param7="";
                       paramsModel.param8="";
                       paramsModel.param9=row.id;
                       paramsModel.param10="";
                       paramsModel.page=1;
                       paramsModel.rows=10;
                       var requestNew = JSON.stringify(paramsModel);
                       requestNew = escape(encodeURIComponent(requestNew));  //处理中文乱码之类
                       $(this).treegrid("options").url =BIMAPIURL+"rest/getConstructionPlanTreeGridDynamic/"+requestNew+"/"+BIMKey+".json";
                   }
               }
           })

那么后台的json数据自然需要rows和total两个属性
		StringBuffer sql=new StringBuffer();
		List<BimPlanComponent> planFileList=new ArrayList<BimPlanComponent>();
		if(StringUtil.isNotEmpty(paramsModel.getParam9())){
			if(paramsModel.getParam9().equals("0")){
				sql.append("select a.id,planName,planStartTime,planEndTime,planTimeLimit,planTimeLimitUnit,planPercentDone,planPriority,planParentId,planIndex,planResource,planRemark,planFileId,planState ");
				sql.append("from BIM_ConstructionPlan as a inner join BIM_ConstructionPlanFile as b on a.planFileId=b.id ");
				sql.append(" inner join t_s_depart as c on b.departId=c.id where 1=1 and a.planParentId is NULL");
				//这里给其添加条件
				sql.append(sqlWhere.toString());
				List<Map<String, Object>> mapList=findForJdbc(sql.toString(),paramsModel.getPage(),paramsModel.getRows());
				//查询出数据的条数
				//不用分页
				if(mapList.size()>0){
					for(Map<String, Object> map:mapList){
						BimPlanComponent plan=new BimPlanComponent();
						plan.setId(String.valueOf(map.get("id")));
						plan.setPlanName(StringUtil.isEmptyObject(map.get("planName"), null));
						plan.setPlanStartTime(GetDate.StrConvertDateShort(StringUtil.isEmptyObject(map.get("planStartTime"),"")));
						plan.setPlanEndTime(GetDate.StrConvertDateShort(StringUtil.isEmptyObject(map.get("planEndTime"),"")));
						plan.setPlanTimeLimit(Integer.parseInt(StringUtil.isEmptyObject(map.get("planTimeLimit"),null)));
						plan.setPlanTimeLimitUnit(StringUtil.isEmptyObject(map.get("planTimeLimitUnit"),null));
						plan.setPlanPercentDone(Double.parseDouble(StringUtil.isEmptyObject(map.get("planPercentDone"),null)));
						plan.setPlanPriority(Integer.parseInt(StringUtil.isEmptyObject(map.get("planPriority"),null)));
						plan.setPlanParentId(StringUtil.isEmptyObject(map.get("planParentId"),null));
						plan.setPlanIndex(Integer.parseInt(StringUtil.isEmptyObject(map.get("planIndex"),null)));
						plan.setPlanResource(StringUtil.isEmptyObject(map.get("planResource"),null));
						plan.setPlanRemark(StringUtil.isEmptyObject(map.get("planRemark"),null));
						plan.setPlanFileId(StringUtil.isEmptyObject(map.get("planFileId"),null));
						plan.setPlanState(StringUtil.isEmptyObject(map.get("planState"),null));
						//设置state
						Long tempLong=getCountForJdbc("select count(*) from BIM_ConstructionPlan where planParentId='"+plan.getId()+"'");
						if(tempLong>0){
							plan.setState("closed");
						}else{
							plan.setState("open");
						}
						planFileList.add(plan);
					}
				}
			}else{
				sql.setLength(0);  //清空sql
			}
		}
		Map<String, Object> map = new HashMap<String, Object>();
		if(planFileList.size()>0){
			map.put("total", dataCount);
			map.put("rows", planFileList);
		}else{
			map.put("total", 0);
			map.put("rows", "[]");
		}
		return map;




版权声明:本文为u011097980原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。