`
八岭书生
  • 浏览: 104086 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

ExtJS实现异步Tree的节点搜索

阅读更多

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


效果图:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

 

Ext.onReady(function() {
            Ext.QuickTips.init();
            Ext.BLANK_IMAGE_URL = "../../resources/images/default/s.gif";
            var mytree = new Ext.tree.TreePanel({
		region: 'center',
		title : "简单Extjs动态树",
                //el : "container",
                animate : true, //展开,收缩动画,false时,则没有动画效果    
                collapsible : true,
                enableDD : true,//不仅可以拖动,还可以通过Drag改变节点的层次结构(drap和drop)
                enableDrag : true,//仅仅drop 
                rootVisible : true,//false不显示根节点,默认为true 
                autoScroll : true,
                autoHeight : true,
                width : 150,
				//tbar:new Ext.Toolbar(),
				tbar:[' ',
					new Ext.form.TextField({
						width:150,
						emptyText:'快速检索',
						enableKeyEvents: true,
						listeners:{
							keyup:function(node, event) {
								findByKeyWordFiler(node, event);
							},
							scope: this
						}
					})
				],
				root:new Ext.tree.AsyncTreeNode({
					id:"root",  
                    text:"树的根",  
                    leaf:false, 
					//expanded:true,
					children: [{
						id: 'level',
						text: '用户类型',
						children: [{
							id: 'allLevel',
							text: '全部',
							leaf: true
						}, {
							id: 'noSupport',
							text: '无支持',
							leaf: true
						}, {
							id: 'month',
							text: '包月',
							leaf: true
						}, {
							id: 'year',
							text: '包年',
							leaf: true
						}, {
							id: 'always',
							text: '终身',
							leaf: true
						}]
					}, {
						id: 'outOfDate',
						text: '是否过期',
						children: [{
							id: 'allOutOfDate',
							text: '全部',
							leaf: true
						}, {
							id: 'notOutOfDate',
							text: '未过期',
							leaf: true
						}, {
							id: 'alreadyOutOfDate',
							text: '已过期',
							leaf: true
						}]
					}, {
						id: 'report',
						text: '统计图表',
						children: [{
							id: 'levelReport',
							text: '按用户类型',
							leaf: true
						}, {
							id: 'outOfDateReport',
							text: '按是否过期',
							leaf: true
						}]
					}]
            }),
                lines : true//节点间的虚线条
            });
			//mytree.expandAll();
            
            //mytree.render();
			/*
			var filterTreeFiled = new Ext.form.TextField({
				width:150,
				emptyText:'快速检索',
				enableKeyEvents: true
			});
			
			var tbar = mytree.getTopToolbar();
			tbar.add(filterTreeFiled);
			tbar.doLayout();*/

			var timeOutId = null;

			var treeFilter = new Ext.tree.TreeFilter(mytree, {
				clearBlank : true,
				autoClear : true
			});

			// 保存上次隐藏的空节点
			var hiddenPkgs = [];
			var findByKeyWordFiler = function(node, event) {
				clearTimeout(timeOutId);// 清除timeOutId
				mytree.expandAll();// 展开树节点
				// 为了避免重复的访问后台,给服务器造成的压力,采用timeOutId进行控制,如果采用treeFilter也可以造成重复的keyup
				timeOutId = setTimeout(function() {
					// 获取输入框的值
					var text = node.getValue();
					// 根据输入制作一个正则表达式,'i'代表不区分大小写
					var re = new RegExp(Ext.escapeRe(text), 'i');
					// 先要显示上次隐藏掉的节点
					Ext.each(hiddenPkgs, function(n) {
						n.ui.show();
					});
					hiddenPkgs = [];
					if (text != "") {
						treeFilter.filterBy(function(n) {
							// 只过滤叶子节点,这样省去枝干被过滤的时候,底下的叶子都无法显示
							return !n.isLeaf() || re.test(n.text);
						});
						// 如果这个节点不是叶子,而且下面没有子节点,就应该隐藏掉
						mytree.root.cascade(function(n) {
							if(n.id!='0'){
								if(!n.isLeaf() &&judge(n,re)==false&& !re.test(n.text)){
									hiddenPkgs.push(n);
									n.ui.hide();
								}
							}
						});
					} else {
						treeFilter.clear();
						return;
					}
				}, 500);
			}
			// 过滤不匹配的非叶子节点或者是叶子节点
			var judge =function(n,re){
				var str=false;
				n.cascade(function(n1){
					if(n1.isLeaf()){
						if(re.test(n1.text)){ str=true;return; }
					} else {
						if(re.test(n1.text)){ str=true;return; }
					}
				});
				return str;
			};
			// 给输入框绑定keyup事件,需要加上enableKeyEvents:true才能让extjs的textfield代理鼠标事件
			//filterTreeFiled.on("keyup", function(node, event) {
				//findByKeyWordFiler(node, event);
			//});

			var eventPanel = new Ext.Panel({
				width  : 680,
				height : 350,
				renderTo : 'container',
				layout: 'border',
				items:[mytree]
			  });
            

        });

 

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

 

<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />
 		<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
		<script type="text/javascript" src="../../ext-all.js"></script>

        <script type="text/javascript" src="treenode.js"></script> 

    <body>
        <div id="container"></div>
    </body>
 

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

 

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

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

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

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

 

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

 

var eventTree = new Ext.tree.TreePanel({
          region: 'center',
          collapsible: false,
          title: '导航',
          xtype: 'treepanel',
          id:'event-west-tree',
          width: 180,
          animate:false, //展开,收缩动画
          autoScroll: true,
          enableDD:true,
          split: true,
          loader: new Ext.tree.TreeLoader({
            dataUrl:'ruleGroupTree.do?json=1'
          }),
          root: new Ext.tree.AsyncTreeNode({
            text: '分类规则组',
            draggable:false,
            //expanded:true, //默认展开第一级
            id:'0'
          }),
          tbar:[{
            iconCls: 'icon-expand-all',
			tooltip: '展开',
            handler: function(){ eventTree.expandAll(); },
            scope: this
          }, '-', {
            iconCls: 'icon-collapse-all',
            tooltip: '收缩',
            handler: function(){ eventTree.collapseAll(); },
            scope: this
          }, new Ext.form.TextField({
				width: 115,
				emptyText:'快速检索',
                enableKeyEvents: true,//给输入框绑定keyup事件,需要加上enableKeyEvents:true才能让extjs的textfield代理鼠标事件
				listeners:{
                    keyup:function(node, event) {
						findByKeyWordFiler(node, event);
					},
                    scope: this
				}
			})]
});

eventTree.expandAll();

var filterTreeFiled = new Ext.form.TextField({
	width:115,
    emptyText:'快速检索',
    enableKeyEvents: true
});
var tbar = eventTree.getTopToolbar();
tbar.add(filterTreeFiled);
tbar.doLayout();



var selectNode = function(node) {
    node.ensureVisible();
    node.select();
    node.fireEvent('click', node);
}

function onExpandPathComplete(bSuccess, oLastNode) {
    if (!bSuccess)
        return;
    // focus 节点,并选中节点!
    selectNode(oLastNode);
}

var findByKeyWordPath = function(node, event) {
    clearTimeout(timeOutId);
    timeOutId = setTimeout(function() {
                var text = node.getValue().trim();
                // 采用ajax获得需要展开的路径
                if (text != "") {
                    Ext.Ajax.request({
                    			params : {
                                    keyWord : text
                                },
                                url : 'ruleGroupTree.do?json=1',
                                method : 'POST',
                                async : false,
                                success : function(response, opts) {
                                    var obj = Ext.decode(response.responseText);
                                    eventTree.expandPath('/0/101/10101','id',onExpandPathComplete);


                                    eventTree.expandPath('/0/101/10101', 'id', function(bSucess,oLastNode){
							          eventTree.getSelectionModel().select(oLastNode);
							        });
                                    if(obj.success){
	                                    var length = obj.length;
	                                    eventTree.root.reload();
	                                    //eventTree.expandAll();
	                                    for (var i = 0; i < length; i++) {
	                                        var path = obj[i].path;
	                                        eventTree.expandPath('/0/101/275','id',onExpandPathComplete);
	                                    }

                                },
                                failure : function(response, opts) {
                                    Ext.Msg.alert("错误提示", "请求失败,请与开发人员联系。").setIcon(Ext.MessageBox.ERROR);
                                }
                            });
                } else {
                }
            }, 500);
}
filterTreeFiled.on("keyup", function(node, event) {
	findByKeyWordPath(node, event);
});
 

 

以下是具体实现:

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文档。

 

分享到:
评论
7 楼 u011703958 2015-03-19  
u011703958 写道
[color=olive][/color]

6 楼 u011703958 2015-03-19  
[color=olive][/color]
5 楼 u011703958 2015-03-19  
         
4 楼 henchong 2013-01-07  
这个我解决了,我的是直接从后台拼接成tree然后返回给前台的。。一次性加载过来
3 楼 pc2004lcq 2013-01-03  
你好,源码能放出来吗?
2 楼 henchong 2012-10-26  
tree一次性加载数据量很多。。这个搜索该怎么解决啊
1 楼 1v1_问天 2012-05-18  
如果客户端返回的path有多个怎么办?后一个path展开就会覆盖前一个path的展开,这个问题怎么解决。

相关推荐

    extjs tree 异步加载树型

    异步加载树型是 ExtJS Tree 的一个重要特性,允许只在需要时动态加载子节点,从而提高页面的加载速度和用户体验。 异步加载通常通过 AJAX 请求实现,只有当用户展开一个节点时,才会向服务器请求该节点的子节点数据...

    ExtJs4 Checkbox tree

    ExtJs4 Checkbox Tree是基于ExtJs 4框架实现的一种特殊树形组件,它在传统的树形结构基础上增加了复选框功能。这种组件常用于需要用户多选树形数据的场景,比如权限设置、目录选择等。下面将详细介绍ExtJs4 Checkbox...

    ExtJS3 实现异步下拉树

    在ExtJS 3中,实现异步下拉树涉及到几个关键概念和技术。 首先,理解“异步”意味着数据不是一次性加载完毕,而是按需加载。在下拉树中,当用户展开树节点时,只加载该节点及其子节点的数据,这减少了初始页面加载...

    extjs的tree的使用

    ExtJS的Tree组件还提供了一系列事件,如`beforeitemexpand`、`itemexpand`、`itemcollapse`等,这些事件可以在节点展开或收起时触发,允许你在这些时刻执行自定义代码,增加更多功能或进行状态管理。 ### 样式与...

    ExtJs_TreeDemo

    "ExtJs_TreeDemo"是一个示例,展示了如何在ExtJs中实现树形菜单的功能。 在ExtJs中,树形菜单(Tree)是通过`Ext.tree.Panel`类来创建的。这个类提供了丰富的配置选项和事件处理机制,使得开发者可以定制各种交互...

    extjs ajax tree(js动态树,无需递归)

    ExtJS AJAX Tree是一种基于JavaScript的动态树形结构,它利用AJAX技术来异步加载节点数据,无需在服务器端生成完整的树结构。这种方式可以显著提高页面加载速度,尤其是在处理大量数据时。ExtJS是一个功能丰富的...

    extjs-tree.zip_extjs tree

    这个"extjs-tree.zip"文件包含了使用Java编写的ExtJS异步树形控件的示例代码,旨在帮助开发者快速理解和应用这一功能。ExtJS是Sencha公司开发的一个前端框架,广泛应用于构建富互联网应用程序(RIA)。 在ExtJS中,...

    ExtJS构造动态异步加载

    本文将深入探讨如何使用ExtJS构建动态异步加载的树形结构,结合AJAX技术实现JSON数据的高效传输。 首先,我们要理解什么是动态异步加载。在传统的网页开发中,如果一次性加载所有数据,可能会导致页面加载速度慢,...

    extjs tree

    ExtJS Tree是基于ExtJS框架实现的一种数据结构展示方式,它主要用于展示层级关系的数据,例如组织结构、文件系统等。ExtJS是一个强大的JavaScript库,专为构建富客户端Web应用程序而设计,提供了丰富的组件化功能和...

    动态加载extjs tree

    在ExtJS Tree中实现动态加载,主要涉及以下几个关键概念: 1. **TreeStore**: TreeStore是ExtJS Tree的数据源,负责管理树节点的数据。它可以配置为从服务器异步获取数据,通过`proxy`配置项来指定数据源类型,通常...

    Extjs的tree

    ExtJS的Tree组件是Sencha ExtJS框架中的一个重要部分,用于构建可交互的树形结构数据展示。在ExtJS中,TreePanel是用来显示和操作树形数据的主要组件,它可以用于组织层次化的信息,如文件系统、组织架构或者分类...

    extjs实现动态树

    在ExtJS中,这种功能主要通过`Ext.tree.TreePanel`或其现代版本`Ext.tree.View`来实现。 一、ExtJS 动态树基础 1. `Ext.tree.TreePanel`:这是ExtJS中用于创建树形结构的主要组件。它具有丰富的配置项和事件,支持...

    Extjs Tree + JSON + Struts2 示例源代码

    ExtJS Tree + JSON + Struts2 示例源代码是结合了三种技术来实现一个动态的、交互式的树形数据展示的应用。这个示例中,ExtJS用于前端UI的构建,JSON作为数据交换格式,而Struts2则作为后端MVC框架处理请求和返回...

    ExtJs Tree

    - **异步加载**:通过`Ext.tree.TreeLoader`实现数据的异步加载,其中`dataUrl`指定了获取数据的URL路径。 - **根节点配置**:通过`root`属性指定树的根节点,该节点可配置自己的`text`、`iconCls`和`id`等属性。 #...

    extJs 2异步树 源程序.

    在Ext Js 2中,实现异步树的关键是使用`TreeLoader`对象。这个对象负责与服务器进行通信,获取并解析JSON数据。JSON数据通常包含节点的ID、文本、子节点数组等信息。例如,一个简单的JSON节点数据可能如下所示: ``...

    extjs tree示例

    ExtJS Tree 示例是一种基于ExtJS库实现的交互式树形组件,它允许用户在Web应用程序中展示层次结构数据。在本示例中,我们将探讨如何使用ExtJS来创建、访问和操作一个树形结构,特别是在数据库操作方面,如添加和删除...

    extjs 树 搜索

    7. **异步加载**:对于拥有大量子节点的树,EXTJS支持延迟加载或按需加载。只有当用户展开父节点时,才会请求并加载其子节点,这样可以显著提高性能。 8. **搜索性能优化**:在处理大量数据时,可以考虑对树进行...

    Extjs3.2.0+asp.net动态Tree

    在3.2.0版本中,TreePanel支持异步加载,可以通过Ajax请求获取节点数据,实现动态加载,提高页面性能。 2. **ASP.NET**:这是一种微软提供的服务器端编程平台,用于构建动态Web应用程序。在这个项目中,ASP.NET可能...

    Extjs chekboxtree PagingTreeLoader 多选、分页

    6. **优化用户体验**: 为了提高用户体验,可以添加异步加载节点的特性,即当用户展开节点时才加载其子节点,这可以通过设置TreeLoader的`async`属性和`loadChildren`方法实现。 总结来说,"Extjs chekboxtree ...

    extjs tree 学习资料

    ExtJS Tree 是一个功能强大的JavaScript组件,用于在Web应用程序中创建和展示层次结构的数据,它在ExtJS框架中扮演着重要角色。这个压缩包“extjs tree 学习资料”显然是为那些希望深入理解并掌握ExtJS Tree组件的...

Global site tag (gtag.js) - Google Analytics