您的位置:首页 > Web前端 > JavaScript

extjs实现全局搜索节点方法

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

效果图:



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

Js代码



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

Html代码



<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.TreePanel 的expandPath 方法展开节点。

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

Js代码



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();

<span style="color: #ff0000;">tbar.add(filterTreeFiled);

tbar.doLayout();</span>

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);

<span style="color: #ff0000;">eventTree.expandPath('/0/101/10101','id',onExpandPathComplete);</span>

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文档。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: