ExtJS2.0实用简明教程》之TreePanel基本使用

在应用程序中,我们经常会涉及到要显示或处理树状结构的对象信息,比如部门信息、地区信息,或者是树状的菜单信息,操作系统中的文件夹信息等。
  对于传统的html页面来说,要自己实现显示树比较困难,需要写很多的javascript,特别是对于基于Ajax异步加载的树来说,不但涉及到Ajax数据加载及处理技术,还需要考虑跨浏览器支持等,处理起来非常麻烦。ExtJS中提供了现存的树控件,通过这些控件可以在B/S应用中快速开发出包含树结构信息的应用。

  TreePanel基本使用

  树控件由Ext.tree.TreePanel类定义,控件的名称为treepanel,TreePanel类继承自Panel面板。在ExtJS中使用树控件其实非常简单,我们先来看下面的代码

Ext.onReady(function(){
 var root=new Ext.tree.TreeNode({
  id:"root",
  text:"树的根"});
 root.appendChild(new Ext.tree.TreeNode({
  id:"c1",
  text:"子节点"
 }));
 var tree=new Ext.tree.TreePanel({
  renderTo:"hello",
  root:root,
  width:100
 });
 });

 

  代码的第一句使用new Ext.tree.TreeNode类来创建一个树节点,第二句使用树节点的root的appendChild方法来往该节点中加入一个子节点,最后直接使用new Ext.tree.TreePanel来创建一个树面板,要树面板的初始化参数中指定树的root属性值为前面创建的root节点,也就是树根节点。上面的程序执行效果如下图所示:

 

   树的节点信息。ExtJS的树控件提供了对这种功能的支持,你只需要在创建树控件的时候,通过给树指定一个节点加载器,可以用来从服务器端动态加载树的节点信息。我们来看下面的代码:

var root=new Ext.tree.AsyncTreeNode({
  id:"root",
  text:"树的根"});
 var tree=new Ext.tree.TreePanel({
  renderTo:"hello",
  root:root,
  loader: new Ext.tree.TreeLoader({url:"treedata.js"}),
  width:100
 });

 

treedata.js这个url返回的内容如下:

[{
        id: 1,
        text: '子节点1',
        leaf: true
    },{
        id: 2,
        text: '儿子节点2',
        children: [{
            id: 3,
            text: '孙子节点',
            leaf: true
        }]
    }]

执行上面的程序,可以得到一棵异步加载子节点的树,点击“根节点”会到服务器端加载子节点,如下图所示:

 

   当然上面的程序是一次性加载完了树的所有节点信息,我们也可以实现让每一个节点都支持动态加载的树,只需要在通过服务器请求数据的时候,每次服务器端返回的数据只只包含子节点,而不用把孙子节点也返回即可。比如把上面treedata.js中的内容改为下面的内容:

[{
        id: 1,
        text: '子节点',
        leaf: false
     }]

  也就是节点树中只包含一个子节点,而该子节点通过指定leaf值为false (默认情况该值为false),表示该节点不是一个叶子节点,其下面还有指节点。再执行前面的程序,不断点击“子节点”可以得到如下图所示的效果:

 

  当然这是一个无限循环的树,在实际应用中我们服务器端返回的数据是程序动态产生的,因此不可能每一次都产生leaf为false的节点,如果是叶子节点的时候,则需要把返回的JOSN对象中的leaf设置为true。如下所示:

[{
        id: 1,
        text: '子节点',
        leaf:true
    }]

  事件处理

  当然,仅仅能显示一棵树还不够,我们一般还需要在用户点击树节点的时候执行相应的东西,比如打开某一个连接,执行某一个函数等,这就需要使用到事件处理。比如下面的代码:

Ext.onReady(function(){
 var root=new Ext.tree.TreeNode({
  id:"root",
  text:"树的根"});
 var c1=new Ext.tree.TreeNode({
  id:"c1",  
  text:"子节点"
 });
 root.appendChild(c1);
 var tree=new Ext.tree.TreePanel({
  renderTo:"hello",
  root:root,
  width:100
 });
 tree.on("click",function(node,event){
  alert("您点击了"+node.text);
 }
 );
 c1.on("click",function(node,event){
  alert("您点击了"+node.text);
 }
 );
 
 });

   执行上面的程序,当用户点击树控件中的任意节点时,都会弹出一个提示信息框,当用户点击c1这个子节点时,会弹出两次提示信息框。因为我们除了指定tree的click事件响应函数以外,另外又给node节点指定单独的事件响应函数。
  
  当然,如果只是要实现当点击树节点时跳到某一个指定url的功能则非常简单。看下面的代码:

Ext.onReady(function(){
 var root=new Ext.tree.TreeNode({
  id:"root",
  href:"http://www.easyjf.com",
  hrefTarget:"_blank",
  text:"树的根"});
 var c1=new Ext.tree.TreeNode({
  id:"c1", 
  href:"http://wlr.easyjf.com", 
  hrefTarget:"_blank",
  text:"子节点"
 });
 root.appendChild(c1);
 var tree=new Ext.tree.TreePanel({
  renderTo:"hello",
  root:root,
  width:100
 });
 
  });

  执行程序,点击树节点,将会在浏览新窗口中打开节点中href指定的链接。

《ExtJS2.0实用简明教程》之使用树控件TreeNode

在ExtJS中,不管是叶子节点还是非叶子节点,都统一用TreeNode表表示树的节点。在ExtJS中,有两种类型的树节点。一种节点是普通的简单树节点,由Ext.tree.TreeNode定义,另外一种是需要异步加载子节点信息的树节点,该类由Ext.tree.AsyncTreeNode定义。 看下面的代码:

Ext.onReady(function(){ 
 var tree=new Ext.tree.TreePanel({
  renderTo:"hello",
  root:new Ext.tree.AsyncTreeNode({  
  text:"根节点"
  }),
  width:100
 }); 
 });

  执行程序,点击树中的“根节点”则会一直发现树会尝试加载这个节点的子节点,由这里没有指定树的加载器,所以“根节点”会变成一直处于加载的状态。如下图所示:

 

  对于普通的TreeNode来说,可以通过调用节点的appendChild、removeChild等方法来往该节点中加入子节点或删除子节点等操作。

  TreeNode与AsyncTreeNode可以同时使用,比如下面的代码:

Ext.onReady(function(){

 var root=new Ext.tree.TreeNode({
  id:"root", 
  text:"树的根"
  }); 
 var c1=new Ext.tree.TreeNode({
  text:"子节点1"
 })
 var c2=new Ext.tree.AsyncTreeNode({
  text:"子节点2"
 });
 root.appendChild(c1);
 root.appendChild(c2); 
 var tree=new Ext.tree.TreePanel({
  renderTo:"hello",
  root:root,
  width:300,
  loader:new Ext.tree.TreeLoader({
  applyLoader:false,
  url:"treedata.js"
  })
 });
 
 });
 treedata.js中的内容仍然是:
[{
        id: 1,
        text: '子节点'
     }]

  执行上面的程序可以得到一棵如下图所示的树:

 

   另外要在树以外的程序中得到当前选择的节点,可以通过TreePanel的getSelectionModel方法来获得,该方法默认返回的是Ext.tree.DefaultSelectionModel对象,DefaultSelectionModel的getSelectedNode方法返回当前选择的树节点。比如要得到树tree中中当前选择节点,代码如下:

tree.getSelectionModel().getSelectedNode()

《ExtJS2.0实用简明教程》之使用树控件TreeLoader

对于ExtJS中的树来说,树加载器TreeLoader是一个比较关键的部件,树加载器由Ext.tree.TreeLoader类定义,只有AsyncTreeNode才会使用TreeLoader。看下面的代码:

Ext.onReady(function(){

 var loader=new Ext.tree.TreeLoader({
  url:"treedata.js"
 });
 var root=new Ext.tree.AsyncTreeNode({
  id:"root", 
  text:"根节点",
  loader:loader}); 
 var tree=new Ext.tree.TreePanel({
  renderTo:"hello",
  root:root,
  width:100
 });
 
 });

  首先我们使用Ext.tree.TreeLoader来初始化了一个TreeLoader对象,构造函数中的配置参数url表示获得树节点信息的url。然后在初始化根节点的时候我们使用的是AsyncTreeNode,在该节点中指定该节点的laoder为前面定义的loader。执行这段程序,在点击“根节点”时,会从服务器端指定root节点的子节点信息。

  TreeLoader严格来说是针对树的节点来定义的,可以给树中的每一个节点定义不同的TreeLoader,默认情况下,如果一个AsyncTreeNode节点在准备加载子节点的时候,如果该节点上没有定义loader,则会使用TreePanel中定义的loader作为加载器。因此,我们可以直接在TreePanel上面指定loader属性,这样就不需要给每一个节点指定具体的TreeLoader了。因此,上面的代码可以改成如下所示的内容:

《ExtJS2.0实用简明教程》之自定义TreeLoader

在ExtJS自己的TreeLoader中,当要实现从远程服务器端异步加载树节点信息的时候,都是通过请求服务器上的某一个URL来进行的,这个URL返回下面的信息:

[{
         id: 1,
         text: 'A leaf Node',
         leaf: true
     },{
         id: 2,
         text: 'A folder Node',
         children: [{
             id: 3,
             text: 'A child Node',
             leaf: true
         }]
    }]

   假如我们是直接通过类似DWR或EasyJWeb的远程脚本引擎在客户端直接调用服务器的业务方法,直接跳过了WEB(不需要Struts、JSP或其它Web层的代码)这一层,这时我们没有URL,这时该怎么办呢?这就需要使用到自定义的TreeLoader,下面我们通过一个实例来做简单的讲解。
看服务器端的ITopicCategoryService
public interface ITopicCategoryService {
List loadCategory(Long id);
}
    loadCategory方法返回一个类型为Node的列表,也就是返回指定id的下级分类信节点信息,Node对应树节点的信息,代码如下:

public class Node {
 private TopicCategory category;
 Node(TopicCategory category) {
  this.category = category;
 }
 public String getId() {
  return category.getId().toString();
 }
 public boolean getLeaf() {
  return category.getChildren().size() < 1;
 }
 public String getText() {
  return category.getName();
 }
 public String getQtip() {
  return category.getName();
 }
 }

    Node在这里相当于一个简单适配器,其实就是把数据库中的日志分类实体适配成包树节点对象。

把ITopicCategoryService发布成可供客户端远程调用,使用EasyJWeb的话引如下面三个js:

<script type="text/javascript" src="/ejf/easyajax/prototype.js"></script>
<script type="text/javascript" src="/ejf/easyajax/engine.js"></script>
<script type="text/javascript" src="/ejf/easyajax/topicCategoryService.js"></script>

    使用DWR的话引入下面的两个js:

<script type="text/javascript" src="/dwr/dwr/engine.js "></script>
<script type="text/javascript" src="/dwr/dwr/util.js "></script>
<script type="text/javascript" src="/dwr/dwr/interface/ topicCategoryService.js "></script>

     这样我们可以在页使用下面的javascrpt来从服务器端获得某一个节点的子节点信息,代码如下:

function test()
{
topicCategoryService.loadCategory(1,function(ret)
{
alert("一共有"+ret.length+"个子节点");
}
}

   如何让ExtJS的树面板能通过这个远程web脚本方法topicCategoryService.loadCategory来加载异步加载树节点信息呢?其实很简单,跟一般的使用没什么两样,树面板TreePanel的代码如下:

var tree = new Ext.tree.TreePanel({
        autoScroll:true,
        animate:true,
        width:'100px',
        height:'300px',
        enableDD:true,
        containerScroll: true, 
        loader: loader
  root: new Ext.tree.AsyncTreeNode({
        text: '日志分类',
               id:'root'
     });
    });

然后区别是在loader部分,使用远程Web调用来加载树节点的loader,代码如下:

var loader=new WebInvokeTreeLoader({
 fn:topicCategoryService.loadCategory
}); 
loader.on("beforeload",function(l,node){
   l.args[0]=(node.id!='root'?node.id:"-1");
   });

再回顾一下传统的直接通过url加载树节点的TreeLoader代码,如下所示:

var loader=new Ext.tree.TreeLoader({
            url:'/topicCategory.ejf?cmd=getCategory&pageSize=-1&treeData=true'            
        });
loader.on("beforeloader",function(loader,node){
   loader.baseParams.id=(node.id!='root'?node.id:"");
   });

    区别在于,远程脚本调用方式加载树节点信息使用的是WebInvokeTreeLoader,需要通过fn属性来指定用于加载数据的远程方法,并在beforeload事件处理器设置参数远程方法调用的参数值。而传统的树节点加载器是Ext.tree.TreeLoader,需要指定一个url来获得json数据。

    WebInvokeTreeLoader是自定义的树加载器,代码其实比较简单,你可以自己写一个。本方案仅供参考,关于WebInvokeTreeLoader的源代码我已经传到了我用ExtJS开发的Blog示例网站上了,仅供VIP会员浏览,有兴趣的朋友可跟我联系。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值