这段时间用到zTree这个插件,但是由于zTree的各个版本的方法好多不共用,所以写了一个动态加载zTree的demo;
运用zTree还是得研究API,然后在网上查询例子再理解改进;下面就我的理解给大家展示一个树的的动态加载方法:
zTree3.5的API:http://www.treejs.cn/v3/api.php
1,在jsp里现有一个tree的载体,zTree的插件和样式一定要引用
<!-- 引用zTree的插件¨ -->
<link type="text/css" rel="stylesheet" href="plugins/zTree/3.5/zTreeStyle.css" />
<script type="text/javascript" src="plugins/zTree/3.5/jquery.ztree.core-3.5.js"></script>
<script type="text/javascript" src="plugins/zTree/jquery.ztree.excheck.js"></script>
<table style="width: 100%;" border="0">
<tr>
<td style="width: 15%;" valign="top" bgcolor="#F9F9F9">
<ul id="leftTree" class="ztree"></ul>
</td>
<td style="width: 85%;" valign="top">
<iframe name="treeFrame" id="treeFrame" frameborder="0" src="<%=basePath%>/byjh/listsx.do?BYMB_ID=0¤tPage=${null == pd.dnowPage || '' == pd.dnowPage?'1':pd.dnowPage}"style="margin: 0 auto; width: 100%; height: 100%;"></iframe>
</td>
</tr>
</table>
2.在jsp里写js方法
<script type="text/javascript">
var zNodes;//设置全局变量来储存节点
var zTree;//定义树对象
/*初始化先异步查询根节点*/
$(function() {
$.ajax({
cache : true,
type : "POST",
url : "byjh/listTreeAsync?isroot=true&YYXYDM="+$("#YYXYDM").val(),
async : false,
success : function(data) {//data是后台传过来的字符串,需用JSON.parse()转成json串,不推荐使用eval(),这个函数不安全
zNodes = JSON.parse(data.data);
},
error : function(data) {
alert("error");
}
});
zTree = $.fn.zTree.init($("#leftTree"), setting, zNodes);//初始化树节点
//zTree.expandNode(zTree.getNodes()[0], true, false, true);
var treeObj = $.fn.zTree.getZTreeObj("#leftTree");//打开第一层树节点
var nodes = treeObj.getNodes();
if (nodes.length>0) {
for(var i=0;i<nodes.length;i++){
treeObj.expandNode(nodes[i], true, false, false);
}
}
})
/*设置树的基本配置信息*/
var setting = {
view : {
nameIsHTML : true
},
check : {
enable : true,
chkStyle : "radio",//设置单端按钮check的话就是复选框
chkboxType : {
"Y" : "s",
"N" : "ps"
},
radioType : "all"
},
data : {
simpleData : {
enable : true
},
keep : {
parent : true
}
},
open : false,
callback : {
onCheck : getonClickedNode,//单选框/复选框选中事件
onClick : getonClickedNode,//单机事件
onExpand : function(event, treeId, treeNode) {//打开事件
addSubNode(treeNode);
}
}
};
//展开子节点函数
function nodeClick(event, treeId, treeNode, clickFlag) {
addSubNode(treeNode);//追加子节点
}
//异步调用后台函数,添加节点数据
function addSubNode(treeNode) {
if(!zTree.getNodeByParam("pId",treeNode.id)){//根据父节点的ID,过滤子节点的父节点是否已被打开过,打开后则不再重新加载,该方法存在bugger,不能实时的加载后台数据
$.ajax({
cache : true,
type : "POST",
url : "byjh/listTreeAsync",
data : {
id:treeNode.id,
MBMC:treeNode.MBMC,
pId:treeNode.ppId,
dj:treeNode.dj,
isroot:'false' ,
TYMCFLDM :treeNode.TYMCFLDM
},
async : true,
success : function(data) {
zTree.addNodes(treeNode, JSON.parse(data.data));//追加子节点
},
error : function(data) {
alert("error");
}
});
}
}
//获取所有被选中节点的值
function getonClickedNode(e, treeId, treeNode) {
var treeObjs = $.fn.zTree.getZTreeObj("leftTree");
treeObjs.selectNode(treeNode, false, false);
treeObjs.checkNode(treeNode, true, true);
var selectno = treeObjs.getCheckedNodes();
var treeNode = selectno[0];
$("#MBMC").val(treeNode.MBMC);
$("#BYMB_ID").val(treeNode.id);
}
//关闭返回节点
function closeX(){
if($("#BYMB_ID").val()=='' || $("#BYMB_ID").val()==null){
bootbox.alert({
buttons: {
ok: {
label: '确定',
className: 'btn btn-mini btn-primary'
}
},
message: '请选择模板!',
title: "",
});
}else{
var BYMB_ID=$("#BYMB_ID").val();
var MBMC=$("#MBMC").val();
var tbodyObj = document.getElementById('simple-table');
var selectedData = [];
selectedData.push({BYMB_ID:BYMB_ID,MBMC:MBMC});
var jsonobj=JSON.stringify(selectedData);//格式化数据
//jsonobj = encodeURI(jsonobj);
$("#xxxid").val(jsonobj);
top.Dialog.close('000');
}
};
</script>
3.后台action方法,用来调用后台查询树的数据,由于我用的框架是bootstrap+springmvc + mybitas,所以action里传递的都是string字符串,action里查询的json串得转化,
/**
* 显示列表ztree
* @param model
* @return
*/
@RequestMapping(value="/listTreeAsync" ,produces="application/json;charset=UTF-8")
@ResponseBody
public Object listTreeAsync(Model model,String DTM_ID)throws Exception{
User user = (User) Jurisdiction.getSession().getAttribute(Const.SESSION_USER);
Map<String,String> map = new HashMap<String,String>();
String json = "";
PageData pd = this.getPageData();
try{
pd.put("CUSERTYSHXYDM", user.getTYSHXYDM());
pd.put("ORGLB", Const.JJLB_YY);
pd.put("BYZD1", "2");//机构等级
//pd.put("NAME", pd.get("YYMC"));
List<PageData> tree = bymbService.listTreesync(pd);
JSONArray arr = JSONArray.fromObject(tree);
json = arr.toString();
json = json.replaceAll("ORGAN_ID", "id").replaceAll("PARENT_ID", "pId").replaceAll("NAME", "name").replaceAll("subOrgan", "nodes").replaceAll("hasOrgan", "checked").replaceAll("treeurl", "url").replace("parent", "isParent").replaceAll("bymb/list?", "byjh/listsx");
} catch(Exception e){
logger.error(e.toString(), e);
}
map.put("data", json);
map.put("msg", json);
return AppUtil.returnObject(pd, map);
}
4.对于service的实现类需自己构造树节点,由于我这个树的每一层都是来自不同的表,为了防止树节点重复加载的问题,需给每个节点构造一个父节点;若果是同一个表存在上下级结构的,就不用考虑这个问题;
/**
* 通用获取网格树形结构 (异步)
* @param MENU_ID
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public List<PageData> listTreesync(PageData pd) throws Exception {
List<PageData> valueList = new ArrayList<PageData>();
if("true".equals(pd.get("isroot"))) {//根节点
valueList = this.listMbdt(pd);
} else if("1".equals(pd.get("dj"))) {//风险等级
PageData fxdj = new PageData();
fxdj.put("pId", pd.get("id"));
fxdj.put("ppId", pd.get("id"));
fxdj.put("dj", "2");
fxdj.put("id", pd.get("id")+"-FX");
fxdj.put("name", "风险等级");
fxdj.put("MBMC", pd.get("MBMC")+"/风险等级");
fxdj.put("target", "treeFrame");
fxdj.put("icon", "static/images/checkx.png");
fxdj.put("treeurl", "bymb/list?BYMB_ID="+ pd.get("id") +"&MBMC="+pd.get("name")+"/风险等级");
if("CK".equals(pd.get("flag_z"))){
fxdj.put("nocheck", "true");
}
pd.put("ZD_CODE", "FXDJ");
List<PageData> zddj = (List<PageData>) dao.findForList("DictionariesMapper.listAllDic", pd);
if(zddj==null || zddj.size()<=0){
fxdj.put("isParent",false);
}else{
fxdj.put("isParent",true);
}
valueList.add(fxdj);
} else if("2".equals(pd.get("dj"))) {//风险等级
valueList = this.Fxdjdt(pd);
}else if("3".equals(pd.get("dj"))) {//通用名称分类
valueList = this.tymcfldt(pd);
}else if("4".equals(pd.get("dj"))) {//通用名称
valueList = this.tymcdt(pd);
}else if("5".equals(pd.get("dj"))) {//模版等级
valueList = this.mbdjdt(pd);
}
return valueList;
}
/**
* 构造医院树
* @param MENU_ID
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public List<PageData> listMbdt(PageData pd) throws Exception {
List<PageData> yyList = (List<PageData>)dao.findForList("OrgTreeMapper.listAll", pd);
List<PageData> oList = new ArrayList<PageData>();
if(yyList!=null&&yyList.size()>0){
for(PageData yy : yyList){
PageData yyy = new PageData();
String id = yy.getString("TYSHXYDM");
yyy.put("id", yy.get("TYSHXYDM"));
yyy.put("pId", yy.get("TYSHXYDM")+"0");
yyy.put("dj", "1");
yyy.put("ppId", yy.get("TYSHXYDM")+"0");
yyy.put("name", yy.get("NAME"));
yyy.put("MBMC", yy.get("NAME"));
yyy.put("treeurl", "bymb/list?BYMB_ID="+ id +"&MBMC="+yy.get("NAME"));
yyy.put("target", "treeFrame");
yyy.put("isParent", true);
yyy.put("flag_z", pd.get("flag_z"));
if("CK".equals(pd.get("flag_z"))){
yyy.put("nocheck", "true");
}
oList.add(yyy);
}
}
return oList;
}
/**
* 构造风险等级树节点
* @param MENU_ID
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public List<PageData> Fxdjdt(PageData pd) throws Exception {
pd.put("ZD_CODE", "FXDJ");
List<PageData> zddj = (List<PageData>) dao.findForList("DictionariesMapper.listAllDic", pd);
if(zddj!=null&&zddj.size()>0){
for(PageData fx : zddj){
String id = pd.getString("id");
id = id+"-"+fx.get("BIANMA");
String MBMC = pd.getString("MBMC");
MBMC = MBMC+"/"+fx.get("NAME");
fx.put("id", id);
fx.put("MBMC",MBMC);
fx.put("pId",pd.getString("id"));
fx.put("dj", "3");
fx.put("ppId", "2");
fx.put("name", fx.get("NAME"));
fx.put("target", "treeFrame");
fx.put("treeurl", "bymb/list?BYMB_ID="+ id +"&MBMC="+MBMC);
fx.put("flag_z", pd.get("flag_z"));
fx.put("icon", "static/images/checkfa.png");
if("CK".equals(pd.get("flag_z"))){
fx.put("nocheck", "true");
}
List<PageData> tymcfl = (List<PageData>)dao.findForList("SbxxMapper.queryTymcFl", pd);
if(tymcfl==null || tymcfl.size()<=0){
fx.put("isParent",false);
}else{
fx.put("isParent",true);
}
}
}
return zddj;
}
/**
* 构造通用名称分类树节点
* @param MENU_ID
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public List<PageData> tymcfldt(PageData pd) throws Exception {
List<PageData> tymcfl = (List<PageData>)dao.findForList("SbxxMapper.queryTymcFl", pd);
if(tymcfl!=null&&tymcfl.size()>0){
for(PageData fl : tymcfl){
String id = pd.getString("id");
id = id+"-"+fl.get("TYMCFLDM");
String MBMC = pd.getString("MBMC");
MBMC = MBMC+"/"+fl.get("TYMCFLMC");
fl.put("id", id);
fl.put("MBMC",MBMC);
fl.put("pId",pd.getString("id"));
fl.put("ppId", "3");
fl.put("dj", "4");
fl.put("name", fl.get("TYMCFLMC"));
fl.put("treeurl", "bymb/list?BYMB_ID="+ id +"&MBMC="+MBMC);
fl.put("target", "treeFrame");
fl.put("flag_z", pd.get("flag_z"));
fl.put("icon", "static/images/checkfa.png");
if("CK".equals(pd.get("flag_z"))){
fl.put("nocheck", "true");
}
List<PageData> inxx = (List<PageData>)dao.findForList("SbxxMapper.queryTymcbyfl", fl);
if(inxx==null || inxx.size()<=0){
fl.put("isParent",false);
}else{
fl.put("isParent",true);
}
}
}
return tymcfl;
}
/**
* 构造通用名称树节点
* @param MENU_ID
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public List<PageData> tymcdt(PageData pd) throws Exception {
List<PageData> tymc = (List<PageData>)dao.findForList("SbxxMapper.queryTymcbyfl", pd);
if(tymc!=null&&tymc.size()>0){
for(PageData fl : tymc){
String id = pd.getString("id");
id = id+"-"+fl.get("TYMCDM");
String MBMC = pd.getString("MBMC");
MBMC = MBMC+"/"+fl.get("TYMC");
fl.put("id", id);
fl.put("MBMC",MBMC);
fl.put("pId",pd.getString("id"));
fl.put("ppId", "4");
fl.put("dj", "5");
fl.put("name", fl.get("TYMC"));
fl.put("treeurl", "bymb/list?BYMB_ID="+ id +"&MBMC="+MBMC);
fl.put("target", "treeFrame");
fl.put("flag_z", pd.get("flag_z"));
fl.put("icon", "static/images/checkfa.png");
if("CK".equals(pd.get("flag_z"))){
fl.put("nocheck", "true");
}
pd.put("ZD_CODE", "MBDJ");
List<PageData> inxx = (List<PageData>) dao.findForList("DictionariesMapper.listAllDic", pd);
if(inxx==null || inxx.size()<=0){
fl.put("isParent",false);
}else{
fl.put("isParent",true);
}
}
}
return tymc;
}
/**
* 构造模板等级树节点
* @param MENU_ID
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public List<PageData> mbdjdt(PageData pd) throws Exception {
pd.put("ZD_CODE", "MBDJ");
List<PageData> mbdj = (List<PageData>) dao.findForList("DictionariesMapper.listAllDic", pd);
if(mbdj!=null&&mbdj.size()>0){
for(PageData fl : mbdj){
String id = pd.getString("id");
id = id+"-"+fl.get("BIANMA");
String MBMC = pd.getString("MBMC");
MBMC = MBMC+"/"+fl.get("NAME");
fl.put("id", id);
fl.put("name", fl.get("NAME"));
fl.put("pId",pd.getString("id"));
fl.put("ppId", "5");
fl.put("dj", "6");
fl.put("treeurl", "bymb/list?BYMB_ID="+ id +"&MBMC="+MBMC);
fl.put("target", "treeFrame");
fl.put("flag_z", pd.get("flag_z"));
fl.put("icon", "static/images/checkfa.png");
fl.put("isParent",false);
if("CK".equals(pd.get("flag_z"))){
fl.put("nocheck", "true");
}
}
}
return mbdj;
}
对应的xml查询数据库的SQL不在这里赘述了,就是一般的SELECT,这样就能实现多表构造树动态加载;
这里需要注意的是addNodes方法,这是一个无赖的,只要是用它就会追加,所以在用动态加载的时候需要用一个字段类区分下面的子节点时候被加载过,如果被加载了就不在调用动态ajax方法去查询后台数据;这样也有一个弊端是不能在一个时间段获取最新的子节点数据,利弊都有吧。网上也有说可以每次都把父节点下的子节点先清掉,然后每次都加载新的就可以解决这个问题,我没能实现,哪位大神要是实现了,请留言,谢谢