jsTree pre1.0使用笔记(上)

 jsTree的使用文档还是不够详细。这里,根据项目需要,自己实作了基于jsTree的显示源代码结构的树:

源码树结构

核心代码如下:

 

  
  
  
  
  1. <script type="text/javascript" class="source below">     
  2.     var only_show_checked_except = false
  3.     var show_called_function = false
  4.     var show_interface_and_method; 
  5.      
  6.     jQuery(document).ready(function(){   
  7. // 初始化jsTree
  8.         jQuery("#src_structure_tree") 
  9.         .bind("before.jstree", function (e, data) { 
  10.              
  11.         }) 
  12.         .bind("after_open.jstree", function(event, data){ 
  13.             
  14.         }) 
  15.         .jstree({  
  16.             // List of active plugins 
  17.             // 注意:需要把"dnd","crrm","cookies","contextmenu"插件去掉! 
  18.             "plugins" : [  
  19.                 "themes","json_data","checkbox","ui","contextmenu","search","types","hotkeys"  
  20.             ], 
  21.              
  22.             "contextmenu": {   
  23.                 "items": {   
  24.                     "create": null,   
  25.                     "rename": null,   
  26.                     "remove": null,   
  27.                     "ccp": null,   
  28.                     "expand": {   
  29.                         "label": "展开",   
  30.                         "action": function (obj) {  
  31.                             //jQuery('#src_structure_tree').jstree('open_all'); 
  32.                             jQuery('#src_structure_tree').jstree('open_all', obj);  
  33.                         }   
  34.                     } 
  35.                 } 
  36.             }, 
  37.              
  38.             // I usually configure the plugin that handles the data first 
  39.             // This example uses JSON as it is most common 
  40.             "json_data" : {  
  41.                 // This tree is ajax enabled - as this is most common, and maybe a bit more complex 
  42.                 // All the options are almost the same as jQuery's AJAX (read the docs) 
  43.                 "ajax" : { 
  44.                     // the URL to fetch the data 
  45.                     "url" : "getSrcStructure.action?appProfileId=${fiBean.appProfile.id}", 
  46.                     // the `data` function is executed in the instance's scope 
  47.                     // the parameter is the node being loaded  
  48.                     // (may be -1, 0, or undefined when loading the root nodes) 
  49.                     "data" : function (n) {  
  50.                         // the result is fed to the AJAX request `data` option 
  51.                         return {  
  52.                             "operation" : "get_children",  
  53.                             "id" : n.attr ? n.attr("id") : 0, 
  54.                             "onlyShowCheckedExcept" : only_show_checked_except, 
  55.                             "showCalledFunction" : show_called_function, 
  56.                             "showInterfaceAndMethod" : show_interface_and_method 
  57.                         };  
  58.                     } 
  59.                 } 
  60.             }, 
  61.             "search" : { 
  62.                 "show_only_matches" : true, 
  63.                 "case_insensitive" : true, 
  64.                 "ajax" : { 
  65.                     // the URL to fetch the data 
  66.                     "url" : "getSrcStructure.action?appProfileId=${fiBean.appProfile.id}", 
  67.                     // the `data` function is executed in the instance's scope 
  68.                     // the parameter is the node being loaded  
  69.                     // (may be -1, 0, or undefined when loading the root nodes) 
  70.                     "data" : function (n) {  
  71.                         // the result is fed to the AJAX request `data` option 
  72.                         return {  
  73.                             "operation" : "get_children",  
  74.                             "id" : n.attr ? n.attr("id") : 0, 
  75.                             "onlyShowCheckedExcept" : only_show_checked_except, 
  76.                             "showCalledFunction" : show_called_function, 
  77.                             "showInterfaceAndMethod" : show_interface_and_method 
  78.                         };  
  79.                     } 
  80.                 } 
  81.             }, 
  82.             'types': { 
  83.                 // I set both options to -2, as I do not need depth and children count checking 
  84.      
  85.                 // Those two checks may slow jstree a lot, so use only when needed 
  86.      
  87.                 "max_depth" : -2, 
  88.                 "max_children" : -2, 
  89. // 这里更换图标
  90.                 'types': { 
  91.                     'pkg' : { 
  92.                         'icon' : { 
  93.                             'image' : '<%=rootPath%>/common/jstree/themes/tcc/package_obj.png' 
  94.                         } 
  95.                     }, 
  96.                     'cls' : { 
  97.                         'icon' : { 
  98.                             'image' : '<%=rootPath%>/common/jstree/themes/tcc/class_obj.png' 
  99.                         } 
  100.                     }, 
  101.                     'method' : { 
  102.                         'icon' : { 
  103.                             'image' : '<%=rootPath%>/common/jstree/themes/tcc/methpub_obj.png' 
  104.                         } 
  105.                     }, 
  106.                     'called_method' : { 
  107.                         'icon' : { 
  108.                             'image' : '<%=rootPath%>/common/jstree/themes/tcc/called_method.png' 
  109.                         } 
  110.                     } 
  111.                 } 
  112.             }    
  113.         }); 
  114.      
  115.         // 选择改变事件,此API,文档上基本上只字未提!幸好在一个英文网站上看到解决方案 
  116.         jQuery("#src_structure_tree").bind("change_state.jstree", function (e, d) { 
  117.             getSelected(); 
  118.         }); 
  119.     }); 
  120.      
  121.     var target_pkgs = []; 
  122.     // 带上包名和类名,用'#'连接,注意,不可用美元符 
  123.     var target_clss = []; 
  124.     // 类名和方法名,用'@'连接 
  125.     var target_methods = []; 
  126.      
  127.     var target_called_methods = []; 
  128.      
  129.     // 判断sub是否是str的子串(注意,并非是真子串),不过,这里的情形,刚好是真子串 
  130.     function strContains(str, sub){   
  131.         return (str.indexOf(sub) != -1);   
  132.     } 
  133.       
  134.     function existParentPackage(pkgArr, pkgName) { 
  135.         var exist = false
  136.         jQuery.each(pkgArr, function(key, val) { 
  137.             //回调函数有两个参数,第一个是元素索引,第二个为当前值 
  138.             if (strContains(pkgName, val)) 
  139.                 exist = true
  140.         }); 
  141.          
  142.         return exist; 
  143.     } 
  144.      
  145.     function strArrToStr(strArr) { 
  146.         var result = ""
  147.         var first = true
  148.         jQuery.each(strArr, function(key, val) { 
  149.             //回调函数有两个参数,第一个是元素索引,第二个为当前值(过滤两个特殊函数<init><clinit> 
  150.             if (first == true) { 
  151.                 first = false
  152.                 result += '&nbsp;&nbsp;&nbsp;&nbsp;' + val.replace(/</g,'&lt;').replace(/>/g,'&gt;').replace('#', '包中的').replace('@', '类中的方法').replace('!', '函数中所调用的').replace('@', '类中的方法'); 
  153.             } else { 
  154.                 result += ",<br/>" + '&nbsp;&nbsp;&nbsp;&nbsp;' + val.replace(/</g,'&lt;').replace(/>/g,'&gt;').replace('#', '包中的').replace('@', '类中的方法').replace('!', '函数中所调用的').replace('@', '类中的方法'); 
  155.             } 
  156.         }); 
  157.          
  158.         return result; 
  159.     } 
  160.      
  161.     function strArrToStr2(strArr) { 
  162.         var result = ""
  163.         var first = true
  164.         jQuery.each(strArr, function(key, val) { 
  165.             //回调函数有两个参数,第一个是元素索引,第二个为当前值 
  166.             //注意:这里要用百分号间隔,不可以用逗号或分号,因为逗号和分号均会出现在方法签名中 
  167.             if (first == true) { 
  168.                 first = false
  169.                 result += val; 
  170.             } else { 
  171.                 result += "%" + val; 
  172.             } 
  173.         }); 
  174.          
  175.         return result; 
  176.     } 
  177.      
  178.     function getSelected() { 
  179.         // 重新初始化为空 
  180.         target_pkgs = []; 
  181.         target_clss = []; 
  182.         target_methods = []; 
  183.         target_called_methods = []; 
  184.         // 对选中的元素进行处理 
  185.         jQuery("#src_structure_tree").jstree("get_checked",null,true).each(function(i,n){ 
  186.             var nodeType = jQuery(n).attr("rel"); 
  187.             var pkg = jQuery(n).attr("pkg"); 
  188.             var cls = jQuery(n).attr("cls"); 
  189.             var method = jQuery(n).attr("method"); 
  190.             var called_cls = jQuery(n).attr("called_cls"); 
  191.             var called_method = jQuery(n).attr("called_method"); 
  192.              
  193.             if (nodeType == 'pkg') { 
  194.                 if (!existParentPackage(target_pkgs, pkg)) { 
  195.                     target_pkgs.push(pkg); 
  196.                     return; 
  197.                 } 
  198.             } 
  199.              
  200.             if (nodeType == 'cls') { 
  201.                 //alert("cls:" + cls); 
  202.                 // 如果所在包已经完全被选择,返回 
  203.                 if (existParentPackage(target_pkgs, pkg)) { 
  204.                     return; 
  205.                 } 
  206.                  
  207.                 // 不做去重处理,因为实际上这种情形不可能出现,除非是服务端程序逻辑有问题 
  208.                 target_clss.push(pkg + '#' + cls); 
  209.                 return; 
  210.             } 
  211.              
  212.             if (nodeType == 'method') { 
  213.                 // 如果所在包已经完全被选择,返回 
  214.                 if (existParentPackage(target_pkgs, pkg)) { 
  215.                     return; 
  216.                 } 
  217.                  
  218.                 // 如果所在类已经完全被选择,返回 
  219.                 if (existParentPackage(target_clss, pkg + '#' + cls)) { 
  220.                     return; 
  221.                 } 
  222.                  
  223.                 // 不做去重处理,因为实际上这种情形不可能出现,除非是服务端程序逻辑有问题 
  224.                 target_methods.push(pkg + '#' + cls + '@' + method); 
  225.             } 
  226.              
  227.             if (nodeType == 'called_method') { 
  228.                 target_called_methods.push(pkg + '#' + cls + '@' + method + '!' + called_cls + '@' + called_method); 
  229.             } 
  230.         }); 
  231.          
  232.         var target_pkgs_value = strArrToStr(target_pkgs); 
  233.         var target_clss_value = strArrToStr(target_clss); 
  234.         var target_methods_value = strArrToStr(target_methods); 
  235.         var target_called_methods_value = strArrToStr(target_called_methods); 
  236.                  
  237.         jQuery("#target_pkgs").html(target_pkgs_value); 
  238.         jQuery("#target_clss").html(target_clss_value); 
  239.         jQuery("#target_methods").html(target_methods_value); 
  240.         jQuery("#target_called_methods").html(target_called_methods_value); 
  241.          
  242.         jQuery("#hidden_target_pkgs").val(strArrToStr2(target_pkgs)); 
  243.         jQuery("#hidden_target_clss").val(strArrToStr2(target_clss)); 
  244.         jQuery("#hidden_target_methods").val(strArrToStr2(target_methods)); 
  245.         jQuery("#hidden_target_called_methods").val(strArrToStr2(target_called_methods)); 
  246.          
  247.         if (target_pkgs_value != "") { 
  248.             jQuery("#target_pkgs_result").html("&nbsp;&nbsp;&nbsp;&nbsp;<b>" + target_pkgs_value + "</b>"); 
  249.         } else { 
  250.             jQuery("#target_pkgs_result").html("&nbsp;&nbsp;&nbsp;&nbsp;<b></b>"); 
  251.         } 
  252.          
  253.         if (target_clss_value != "") { 
  254.             jQuery("#target_clss_result").html("&nbsp;&nbsp;&nbsp;&nbsp;<b>" + target_clss_value + "</b>"); 
  255.         } else { 
  256.             jQuery("#target_clss_result").html("&nbsp;&nbsp;&nbsp;&nbsp;<b></b>"); 
  257.         } 
  258.          
  259.         if (target_methods_value != "") { 
  260.             jQuery("#target_methods_result").html("&nbsp;&nbsp;&nbsp;&nbsp;<b>" + target_methods_value + "</b>"); 
  261.         } else { 
  262.             jQuery("#target_methods_result").html("&nbsp;&nbsp;&nbsp;&nbsp;<b></b>"); 
  263.         } 
  264.          
  265.         if (target_called_methods_value != "") { 
  266.             jQuery("#target_called_methods_result").html("&nbsp;&nbsp;&nbsp;&nbsp;<b>" + target_called_methods_value + "</b>"); 
  267.         } else { 
  268.             jQuery("#target_called_methods_result").html("&nbsp;&nbsp;&nbsp;&nbsp;<b></b>"); 
  269.         } 
  270.          
  271.         validateStep1(); 
  272.     } 
  273. </script> 

关键是要理解代码中这句英文注解的意思:

// the result is fed to the AJAX request `data` option 

也就是说,在紧接着的return块的内容(多个键值对),会被post给struts2的action。

 

  1. return {  
  2.                             "operation" : "get_children",  
  3.                             "id" : n.attr ? n.attr("id") : 0, 
  4.                             "onlyShowCheckedExcept" : only_show_checked_except, 
  5.                             "showCalledFunction" : show_called_function, 
  6.                             "showInterfaceAndMethod" : show_interface_and_method 
  7.                         }; 

 

显然,第一次请求发过去的id为0。

相关的服务端处理代码:


 

  
  
  
  
  1. public class SrcStructureAction extends BaseAction { 
  2.  
  3.     private static final long serialVersionUID = 1L; 
  4.  
  5.     private String appProfileId; 
  6.      
  7.     private String id; 
  8.      
  9.     // 是否只显示受检查异常 
  10.     private String onlyShowCheckedExcept; 
  11.      
  12.     // 是否显示函数中被调用的方法 
  13.     private String showCalledFunction; 
  14.      
  15.     // 通过接口和方法名进行过滤 
  16.     private String showInterfaceAndMethod; 
  17.      
  18.     private FaultInjectService faultInjectService; 
  19.      
  20.     public SrcStructureAction() { 
  21.  
  22.     } 
  23.      
  24.     public String getSrcStructure() { 
  25.         if (showInterfaceAndMethod == null) { 
  26.             showInterfaceAndMethod = ""
  27.         } else { 
  28.             showInterfaceAndMethod = showInterfaceAndMethod.trim().replace(".""/"); 
  29.         } 
  30.          
  31.         String result = faultInjectService.getSrcStructureStr(appProfileId, id, onlyShowCheckedExcept, showCalledFunction, showInterfaceAndMethod); 
  32.         writeToClient(result); 
  33.          
  34.         return null
  35.     } 

writeToClient:

 

  
  
  
  
  1. protected void writeToClient(String content) { 
  2.         try { 
  3.             PrintWriter out = getResponseWriter(); 
  4.             out.print(content); 
  5.             out.flush(); 
  6.         } catch (IOException e) { 
  7.             //throw new ServiceException(e.getMessage(),e); 
  8.         } 
  9.     } 

getSrcStructureStr的使命就是返回jsTree可以正确识别的json格式的字符串。根据不同节点的id的值,返回不同的孩子节点信息。

当查询条件改变时,只要更改条件,然后重新刷新树即可,这时jsTree就会重新发起请求,重新构造一棵新的树。

 

  
  
  
  
  1. jQuery('#src_structure_tree').jstree('refresh',-1); 

接下来,展示代码,因为代码太长,分开到下篇阐述。

 

 

你可能感兴趣的:(treenode,jstree,1.0)