extjs实现全局搜索节点方法

来源:互联网 发布:淘宝运营商二次放号 编辑:程序博客网 时间:2024/05/20 11:47

  前言:在任何一个Tree树中,提供查找功能无疑会大大方便用户。不用睁大眼睛一级一级去展开,只要输入关键字,回车就能自动定位到节点,岂不快哉?这样的用户体验是相当完美的。但在动态异步加载 的Tree树中,客户端实现这样的功能就有点困难,因为节点是异步动态加载的。默认是没有全部从服务器端取回 的,通常的做法是默认加载第一级,其他级的节点都是惰性按需加载的,用户点了才会展开。而对于这个没有完全加载的树,用户希望搜索节点,怎么实现?笨办法是先展开树的所有节点,然后再在树中搜索 。这样的话在服务器数据量大的情况下会非常慢。所以在数据量大的情况下,是不采取这种实现方式的,这里的实现方法是在服务器端的Servlet中查找,通过AJAX返回第一个匹配节点的路径Path,然后展开这个路径,选中这个搜索到节点 。


效果图:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

         一、 先展开树的所有节点,然后再在树中搜索

 

Js代码  收藏代码
  1. Ext.onReady(function() {  
  2.             Ext.QuickTips.init();  
  3.             Ext.BLANK_IMAGE_URL = "../../resources/images/default/s.gif";  
  4.             var mytree = new Ext.tree.TreePanel({  
  5.         region: 'center',  
  6.         title : "简单Extjs动态树",  
  7.                 //el : "container",  
  8.                 animate : true//展开,收缩动画,false时,则没有动画效果      
  9.                 collapsible : true,  
  10.                 enableDD : true,//不仅可以拖动,还可以通过Drag改变节点的层次结构(drap和drop)  
  11.                 enableDrag : true,//仅仅drop   
  12.                 rootVisible : true,//false不显示根节点,默认为true   
  13.                 autoScroll : true,  
  14.                 autoHeight : true,  
  15.                 width : 150,  
  16.                 //tbar:new Ext.Toolbar(),  
  17.                 tbar:[' ',  
  18.                     new Ext.form.TextField({  
  19.                         width:150,  
  20.                         emptyText:'快速检索',  
  21.                         enableKeyEvents: true,  
  22.                         listeners:{  
  23.                             keyup:function(node, event) {  
  24.                                 findByKeyWordFiler(node, event);  
  25.                             },  
  26.                             scope: this  
  27.                         }  
  28.                     })  
  29.                 ],  
  30.                 root:new Ext.tree.AsyncTreeNode({  
  31.                     id:"root",    
  32.                     text:"树的根",    
  33.                     leaf:false,   
  34.                     //expanded:true,  
  35.                     children: [{  
  36.                         id: 'level',  
  37.                         text: '用户类型',  
  38.                         children: [{  
  39.                             id: 'allLevel',  
  40.                             text: '全部',  
  41.                             leaf: true  
  42.                         }, {  
  43.                             id: 'noSupport',  
  44.                             text: '无支持',  
  45.                             leaf: true  
  46.                         }, {  
  47.                             id: 'month',  
  48.                             text: '包月',  
  49.                             leaf: true  
  50.                         }, {  
  51.                             id: 'year',  
  52.                             text: '包年',  
  53.                             leaf: true  
  54.                         }, {  
  55.                             id: 'always',  
  56.                             text: '终身',  
  57.                             leaf: true  
  58.                         }]  
  59.                     }, {  
  60.                         id: 'outOfDate',  
  61.                         text: '是否过期',  
  62.                         children: [{  
  63.                             id: 'allOutOfDate',  
  64.                             text: '全部',  
  65.                             leaf: true  
  66.                         }, {  
  67.                             id: 'notOutOfDate',  
  68.                             text: '未过期',  
  69.                             leaf: true  
  70.                         }, {  
  71.                             id: 'alreadyOutOfDate',  
  72.                             text: '已过期',  
  73.                             leaf: true  
  74.                         }]  
  75.                     }, {  
  76.                         id: 'report',  
  77.                         text: '统计图表',  
  78.                         children: [{  
  79.                             id: 'levelReport',  
  80.                             text: '按用户类型',  
  81.                             leaf: true  
  82.                         }, {  
  83.                             id: 'outOfDateReport',  
  84.                             text: '按是否过期',  
  85.                             leaf: true  
  86.                         }]  
  87.                     }]  
  88.             }),  
  89.                 lines : true//节点间的虚线条  
  90.             });  
  91.             //mytree.expandAll();  
  92.               
  93.             //mytree.render();  
  94.             /* 
  95.             var filterTreeFiled = new Ext.form.TextField({ 
  96.                 width:150, 
  97.                 emptyText:'快速检索', 
  98.                 enableKeyEvents: true 
  99.             }); 
  100.              
  101.             var tbar = mytree.getTopToolbar(); 
  102.             tbar.add(filterTreeFiled); 
  103.             tbar.doLayout();*/  
  104.   
  105.             var timeOutId = null;  
  106.   
  107.             var treeFilter = new Ext.tree.TreeFilter(mytree, {  
  108.                 clearBlank : true,  
  109.                 autoClear : true  
  110.             });  
  111.   
  112.             // 保存上次隐藏的空节点  
  113.             var hiddenPkgs = [];  
  114.             var findByKeyWordFiler = function(node, event) {  
  115.                 clearTimeout(timeOutId);// 清除timeOutId  
  116.                 mytree.expandAll();// 展开树节点  
  117.                 // 为了避免重复的访问后台,给服务器造成的压力,采用timeOutId进行控制,如果采用treeFilter也可以造成重复的keyup  
  118.                 timeOutId = setTimeout(function() {  
  119.                     // 获取输入框的值  
  120.                     var text = node.getValue();  
  121.                     // 根据输入制作一个正则表达式,'i'代表不区分大小写  
  122.                     var re = new RegExp(Ext.escapeRe(text), 'i');  
  123.                     // 先要显示上次隐藏掉的节点  
  124.                     Ext.each(hiddenPkgs, function(n) {  
  125.                         n.ui.show();  
  126.                     });  
  127.                     hiddenPkgs = [];  
  128.                     if (text != "") {  
  129.                         treeFilter.filterBy(function(n) {  
  130.                             // 只过滤叶子节点,这样省去枝干被过滤的时候,底下的叶子都无法显示  
  131.                             return !n.isLeaf() || re.test(n.text);  
  132.                         });  
  133.                         // 如果这个节点不是叶子,而且下面没有子节点,就应该隐藏掉  
  134.                         mytree.root.cascade(function(n) {  
  135.                             if(n.id!='0'){  
  136.                                 if(!n.isLeaf() &&judge(n,re)==false&& !re.test(n.text)){  
  137.                                     hiddenPkgs.push(n);  
  138.                                     n.ui.hide();  
  139.                                 }  
  140.                             }  
  141.                         });  
  142.                     } else {  
  143.                         treeFilter.clear();  
  144.                         return;  
  145.                     }  
  146.                 }, 500);  
  147.             }  
  148.             // 过滤不匹配的非叶子节点或者是叶子节点  
  149.             var judge =function(n,re){  
  150.                 var str=false;  
  151.                 n.cascade(function(n1){  
  152.                     if(n1.isLeaf()){  
  153.                         if(re.test(n1.text)){ str=true;return; }  
  154.                     } else {  
  155.                         if(re.test(n1.text)){ str=true;return; }  
  156.                     }  
  157.                 });  
  158.                 return str;  
  159.             };  
  160.             // 给输入框绑定keyup事件,需要加上enableKeyEvents:true才能让extjs的textfield代理鼠标事件  
  161.             //filterTreeFiled.on("keyup", function(node, event) {  
  162.                 //findByKeyWordFiler(node, event);  
  163.             //});  
  164.   
  165.             var eventPanel = new Ext.Panel({  
  166.                 width  : 680,  
  167.                 height : 350,  
  168.                 renderTo : 'container',  
  169.                 layout: 'border',  
  170.                 items:[mytree]  
  171.               });  
  172.               
  173.   
  174.         });  

 

注意ext-base.js和ext-all.js的引用顺序 ,具体的可以查看INCLUDE_ORDER.txt

 

Html代码  收藏代码
  1. <link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />  
  2.         <script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>  
  3.         <script type="text/javascript" src="../../ext-all.js"></script>  
  4.   
  5.         <script type="text/javascript" src="treenode.js"></script>   
  6.   
  7.     <body>  
  8.         <div id="container"></div>  
  9.     </body>  
 

    二、 通过AJAX返回第一个匹配节点的路径Path,然后展开这个路径,选中这个搜索到节点

 

要实现此功能需解决三个问题:

1.  通过Ajax将节点id或text传回服务器。

2.  在服务器端查找到节点path,path由节点id号和“/”构成。注意path的格式,如:'/0/4/7'。此处0表示根节点id,7表示被查找的节点id。

3. 将path传回客服端,Extjs将通过Ext.tree.TreePanel 的expandPath 方法展开节点。

 

在ExtJS中,AsyncTreeNode是异步节点,TreeLoader实现对树结点的异步加载,即使服务器取到大量的数据,也没有问题,异步加载能保证性能和节点的按需加载。服务端需要生成指定格式的Json字符串。

 

Js代码  收藏代码
  1. var eventTree = new Ext.tree.TreePanel({  
  2.           region: 'center',  
  3.           collapsible: false,  
  4.           title: '导航',  
  5.           xtype: 'treepanel',  
  6.           id:'event-west-tree',  
  7.           width: 180,  
  8.           animate:false//展开,收缩动画  
  9.           autoScroll: true,  
  10.           enableDD:true,  
  11.           split: true,  
  12.           loader: new Ext.tree.TreeLoader({  
  13.             dataUrl:'ruleGroupTree.do?json=1'  
  14.           }),  
  15.           root: new Ext.tree.AsyncTreeNode({  
  16.             text: '分类规则组',  
  17.             draggable:false,  
  18.             //expanded:true, //默认展开第一级  
  19.             id:'0'  
  20.           }),  
  21.           tbar:[{  
  22.             iconCls: 'icon-expand-all',  
  23.             tooltip: '展开',  
  24.             handler: function(){ eventTree.expandAll(); },  
  25.             scope: this  
  26.           }, '-', {  
  27.             iconCls: 'icon-collapse-all',  
  28.             tooltip: '收缩',  
  29.             handler: function(){ eventTree.collapseAll(); },  
  30.             scope: this  
  31.           }, new Ext.form.TextField({  
  32.                 width: 115,  
  33.                 emptyText:'快速检索',  
  34.                 enableKeyEvents: true,//给输入框绑定keyup事件,需要加上enableKeyEvents:true才能让extjs的textfield代理鼠标事件  
  35.                 listeners:{  
  36.                     keyup:function(node, event) {  
  37.                         findByKeyWordFiler(node, event);  
  38.                     },  
  39.                     scope: this  
  40.                 }  
  41.             })]  
  42. });  
  43.   
  44. eventTree.expandAll();  
  45.   
  46. var filterTreeFiled = new Ext.form.TextField({  
  47.     width:115,  
  48.     emptyText:'快速检索',  
  49.     enableKeyEvents: true  
  50. });  
  51. var tbar = eventTree.getTopToolbar();  
  52. <span style="color: #ff0000;">tbar.add(filterTreeFiled);  
  53. tbar.doLayout();</span>  
  54.   
  55.   
  56.   
  57. var selectNode = function(node) {  
  58.     node.ensureVisible();  
  59.     node.select();  
  60.     node.fireEvent('click', node);  
  61. }  
  62.   
  63. function onExpandPathComplete(bSuccess, oLastNode) {  
  64.     if (!bSuccess)  
  65.         return;  
  66.     // focus 节点,并选中节点!  
  67.     selectNode(oLastNode);  
  68. }  
  69.   
  70. var findByKeyWordPath = function(node, event) {  
  71.     clearTimeout(timeOutId);  
  72.     timeOutId = setTimeout(function() {  
  73.                 var text = node.getValue().trim();  
  74.                 // 采用ajax获得需要展开的路径  
  75.                 if (text != "") {  
  76.                     Ext.Ajax.request({  
  77.                                 params : {  
  78.                                     keyWord : text  
  79.                                 },  
  80.                                 url : 'ruleGroupTree.do?json=1',  
  81.                                 method : 'POST',  
  82.                                 async : false,  
  83.                                 success : function(response, opts) {  
  84.                                     var obj = Ext.decode(response.responseText);  
  85.                                     <span style="color: #ff0000;">eventTree.expandPath('/0/101/10101','id',onExpandPathComplete);</span>  
  86.   
  87.   
  88.                                     eventTree.expandPath('/0/101/10101''id'function(bSucess,oLastNode){  
  89.                                       eventTree.getSelectionModel().select(oLastNode);  
  90.                                     });  
  91.                                     if(obj.success){  
  92.                                         var length = obj.length;  
  93.                                         eventTree.root.reload();  
  94.                                         //eventTree.expandAll();  
  95.                                         for (var i = 0; i < length; i++) {  
  96.                                             var path = obj[i].path;  
  97.                                             eventTree.expandPath('/0/101/275','id',onExpandPathComplete);  
  98.                                         }  
  99.   
  100.                                 },  
  101.                                 failure : function(response, opts) {  
  102.                                     Ext.Msg.alert("错误提示""请求失败,请与开发人员联系。").setIcon(Ext.MessageBox.ERROR);  
  103.                                 }  
  104.                             });  
  105.                 } else {  
  106.                 }  
  107.             }, 500);  
  108. }  
  109. filterTreeFiled.on("keyup"function(node, event) {  
  110.     findByKeyWordPath(node, event);  
  111. });  
 

 

以下是具体实现:

1. servlet端要实现的功能就是封装path,将path发送到客服端即可,格式如上。代码省略。

2. 客户端代码:

// 查找树节点
 searchNode : function() {
      var searchForm = Ext.getCmp("searchForm").getForm();
      var param = searchForm.getValues();
      if(searchForm.isValid()){
          Ext.Ajax.request({
               url: 'dept!search.action',
               params:{formData:Ext.encode(param)},
               success:function(response){
                   var o = Ext.decode(response.responseText);
                   if(o.success){
                       var tree = Ext.getCmp('sysOrgs');
                       path=o.message;
                       tree.expandPath(path, 'id', this.onExpandPathComplete );
                   }
               },
               failure:function(response){
               },
               scope:this
         });
      }
 },
 onExpandPathComplete: function(bSuccess, oLastNode) {
  if(!bSuccess)
   return;
  //focus 节点,并选中节点!,以下代码不可少 
  oLastNode.ensureVisible();
  oLastNode.select();
  oLastNode.fireEvent('click', oLastNode);
  
 }

关于tree.expandPath方法的使用具体参照API文档。

 

0 0
原创粉丝点击