這段時間用到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 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方法去查詢後臺數據;這樣也有一個弊端是不能在一個時間段獲取最新的子節點數據,利弊都有吧。網上也有說可以每次都把父節點下的子節點先清掉,然後每次都加載新的就可以解決這個問題,我沒能實現,哪位大神要是實現了,請留言,謝謝