lixw 发表于 2013-1-23 02:59:05

Ext Tree使用笔记

      最近做项目对Ext Tree做了一些简单应用,进行一个简单总结,与大家分享。
之前使用dTree,这个JS短小精悍,功能也不逊色,特别是它的cookie记录功能,让我们省了不少的事,不过缺点就是不支持异步查询。后来转换到了Ext Tree上。下面是一些应用场景和总结。欢迎大家指导。
 
1、同步树:
     创建TreePanel,设置属性,添加一个根节点,并展开树。
var Tree = Ext.tree;var tree = new Tree.TreePanel({         el:'treeDiv',         autoScroll:true,      autoHeight:true,      animate:true,      enableDD:true,      loader: new Tree.TreeLoader({    dataUrl:'tree.do'         })});   // set the root node   var root=new Ext.tree.TreeNode({   id : "root",   text : "操作列表"});tree.setRootNode(root);// render the treetree.render();root.expand();root.select(); 
2、异步树:
    为同步树树添加异步子节点,并指定其连接地址。
node.on('expand', getSubTree);    指定展开节点时如何触发异步查询
 
function appendToRoot(root, n){   var roots = document.getElementsByName(n.id);    //alert(roots.length);    if(roots != null){    for(var i = 0; i < roots.length; i++){    var rr = roots.value;    if(rr == null || rr.length == 0){    continue;    }    //alert(rr);    var id_ = rr.split(",");    var text_ = rr.split(",");    var node = null;    var hasChild = rr.split(",");var isLeaf = (hasChild == "true") ? false : true;node = new Ext.tree.AsyncTreeNode({id: id_,text : text_,href : "Handle.do?id=" + id_ ,      hrefTarget : "main",      leaf : isLeaf,children : [{       text : 'loading',       iconCls : 'loading',       leaf : false}]});    node.on('expand', getSubTree);    root.appendChild(node);    }    }    }      异步查找子节点。
function getSubTree(node){if(node.firstChild.text=='loading'){Ext.Ajax.request({url: 'tree.do',params: {node : node.id},method: 'POST',timeout: 60*1000, //1分钟success: function(v){//成功返回var myData = eval(v.responseText); // 得到服务器返回的json串 if(v.responseText == null || myData.length == 0){node.firstChild.remove();return;}for(var i = 0; i < myData.length; i++){var cnode = new Ext.tree.AsyncTreeNode({id : myData.id,text : myData.text,leaf : myData.isLeaf,href : "Handle.do?id=" + myData.id,hrefTarget : TARGET,children : [{                  //添加子节点,如果服务器返回tl.leaf为true则孩子节点将无法显示text : 'loading',iconCls: 'loading',leaf:true}]});cnode.on('expand',getSubTree);node.appendChild(cnode);}node.firstChild.remove();//删除当前节点第一个孩子节点(loading节点)},// 失败failure: function(){alert("获取子节点出错");}});} }      服务器端的代码片段:
public List<Map<String, Object>> getSubTree(String id, String type) {try {List<Map<String, Object>> retList = new ArrayList<Map<String, Object>>();List<ChnTreeNode> list = getManage().getRankingManage().getChilds(id);for(ChnTreeNode node : list) {Map<String, Object> tree = new HashMap<String, Object>();String nodeType = node.getType();if(filterNode(nodeType, type)){continue;}//节点的id    tree.put("id", node.getId());//节点显示单位名            tree.put("text", node.getText());//是否是叶子节点tree.put("isLeaf", Boolean.valueOf(node.isLeaf()));//类型tree.put("type", nodeType);//将这个生成叶子节点对应的MAP加到单位list里   retList.add(tree);}return retList;} catch (Exception e) {log.error("获取子节点列表失败:" + e.getMessage());return null;}}public static boolean filterNode(String nodeType, String type) {if("1".equals(type)){return false;}else{int type_ = Integer.parseInt(type);if(nodeType.substring(type_-2, type_-1).equals("1")){return false;}else{return true;}}}public JSONArray getModuleTree(String id, String type) {List<Map<String, Object>> list = this.getSubTree(id, type);if (list == null) {return null;}//转换这个list让他变成json格式       JSONArray jsonArray = JSONArray.fromObject(list);return jsonArray;}public ActionForward tree(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response) {String id = request.getParameter("node");String type = request.getParameter("filter");JSONArray jsonArray = getModuleTree(id, type);response.setContentType("text/json; charset=GBK");try {response.getWriter().print(jsonArray);} catch (IOException e) {log.error("输出json失败" + e.getMessage());return null;}return null;} 
3、自定义节点属性:
      从2中的服务器端代码看到我们自定义了type属性,这样返回的JSON字符串,就可以获得这个属性设置到树的TreeNode中,那么我们如何取得这个属性呢,可以用这样的代码:
node.attributes.type 4、复选框支持:
      经常有这样的应用场景,就是我们的树节点是支持多选的,这时候我们可以为树节点添加checked属性,监听复选事件,可以用下面的代码:
node.on('checkchange', checkChange);...function checkChange(node, checked){//node.expand();node.attributes.checked = checked;node.eachChild(function(child) {   child.ui.toggleCheck(checked);   child.attributes.checked = checked;child.fireEvent('checkchange', child, checked);   });}     上面的操作还能够实现点选父节点时,将所有它的子节点也选择。如何获得复选框的值呢,请看5.
 
5、递归取值:
     下面的方法是采用递归函数的方式遍历整个节点子树,将所有值保存到了Array中,不知Ext Tree有没有提供这样的功能,如果有,请大家一定要告诉我,谢谢!
function handleSelect(node, chnIds){if(node.attributes.checked){if(!contains(chnIds, node.id)){chnIds.push(node.id);}return;}else{node.eachChild(function(child) {handleSelect(child, chnIds);    });}}  
6、remove的问题:
      先看一段代码:
var children = root.childNodes;for(var i = 0; i < children.length; i++){   root.removeChild(children);}      如果使用上面的代码,我们会发现删除总是会出现逻辑问题,最开始我也很是疑惑,明明length为3,为什么只执行两次呢,原来是删除的同时,root节点孩子的数目和每个孩子所处的下标都是变化的,我们可以用这段代码来代替:
while(root.firstChild){   root.removeChild(root.firstChild);}  
7、TreeFilter的应用:
      TreeFilter可以实现按条件过滤的功能,树的节点在展示的时候,会考虑TreeFilter的过滤来决定显示那些节点,隐藏那些节点,它的用法很简单:
var filter = new Ext.tree.TreeFilter(tree, {    clearBlank: true,    autoClear: true});filter.filterBy(function(n){    if(n.id.substring(0, 1) == "N"){         return false;    }else{         return true;    }});      上面的代码会过滤掉所有id以字母N开头的节点。
 
8、注意事项:
      对于异步树节点,如果不同节点可能来自不同数据表的时候,如果我们利用表的主键做ID,我们要防止节点的ID重复,可以在在取得的主键ID前面增加字符串做标识,后台再截取。
 
9、问题:
     点击历史的记录,这个对于异步树有点难度,大家是怎么做的呢?
     对节点的页面级的缓存
 
参考:
http://beckrabbit.iteye.com/blog/132995
http://kingapex.iteye.com/blog/150806
http://www.iteye.com/topic/133269
http://www.easyjf.com/bbs.ejf?cmd=appShow&id=5734416
http://jstang.5d6d.com/thread-844-1-1.html
页: [1]
查看完整版本: Ext Tree使用笔记