zoukankan      html  css  js  c++  java
  • 第九章 、 TreePanel

    第九章 、 TreePanel

    9.1 、 TreePanel之基本使用


    在 应用程序中,我们经常会涉及到要显示或处理树状结构的对象信息,比如部门信息、地 区
    信息,或者是树状的菜单信息,操作系统中的文件夹信息等。
    对于传统的 html 页面来说,要自己实现显示树比较困难,需要写很多的 javascript ,特
    别是对于基于 Ajax 异步加载的树来说,不但涉及到 Ajax 数据加载及处理技术,还需要考 虑
    跨浏览器支持等,处理起来非常麻烦。 ExtJS 中提供了现存的树控件,通过这些控件可以 在
    B/S 应用中快速开发出包含树结构信息的应用。
    TreePanel TreePanel TreePanel 基本使用
    树控件由 Ext.tree.TreePanel 类定义,控件的名称为 treepanel , TreePanel 类继承自 Pane l
    面板。在 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,
    100
    });
    });

    代码的第一句使用 new Ext.tree.TreeNode 类来创建一个树节点,第二句使用树节点的
    root 的 appendChild 方法来往该节点中加入一个子节点,最后直接使用 new Ext.tree.TreePan el
    来创建一个树面板,要树面板的初始化参数中指定树的 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"}),
    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,
    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,
    100
    });
    });

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

    9.2 、 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:" 根节点 "
    }),
    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,
    300,
    loader:new Ext.tree.TreeLoader({
    applyLoader:false,
    url:"http://www.cnblogs.com/liu2008hz/admin/%22treedata.js"
    })
    });
    });

    treedata.js 中的内容仍然是:
    [{
    id: 1,
    text: ' 子节点 '
    }]

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

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

    9.3 、 TreeLoader

    对于 ExtJS 中的树来说,树加载器 TreeLoader 是一个比较关键的部件,树加载器由
    Ext.tree.TreeLoader 类定义,只有 AsyncTreeNode 才会使用 TreeLoader 。看下面的代码:
    Ext.onReady(function(){
    var loader=new Ext.tree.TreeLoader({
    url:"http://www.cnblogs.com/liu2008hz/admin/%22treedata.js"
    });
    var root=new Ext.tree.AsyncTreeNode({
    id:"root",
    text:" 根节点 ",
    loader:loader});
    var tree=new Ext.tree.TreePanel({
    renderTo:"hello",
    root:root,
    100
    });
    });

    首先我们使用 Ext.tree.TreeLoader 来初始化了一个 TreeLoader 对象,构造函数中的配 置
    数 url 表示获得树节点信息的 url 。然后在初始化根节点的时候我们使用的是
    ncTreeNode ,在该节点中指定该节点的 laoder 为前面定义的 loader 。执行这段程序,在
    击 “ 根节点 ” 时,会从服务器端指定 root 节点的子节点信息。
    TreeLoader 严格来说是针对树的节点来定义的,可以给树中的每一个节点定义不同的
    eLoader ,默认情况下,如果一个 AsyncTreeNode 节点在准备加载子节点的时候,如果 该
    点上没有定义 loader ,则会使用 TreePanel 中定义的 loader 作为加载器。因此,我们可以
    接在 TreePanel 上面指定 loader 属性,这样就不需要给每一个节点指定具体的 TreeLoader
    。因此,上面的代码可以改成如下所示的内容 :

    9.3  、 TreeLoader

    对于 ExtJS 中的树来说,树加载器 TreeLoader 是一个比较关键的部件,树加载器由
    Ext.tree.TreeLoader 类定义,只有 AsyncTreeNode 才会使用 TreeLoader 。看下面的代码:
    Ext.onReady(function(){
    var loader=new Ext.tree.TreeLoader({
    url:"http://www.cnblogs.com/liu2008hz/admin/%22treedata.js"
    });
    var root=new Ext.tree.AsyncTreeNode({
    id:"root",
    text:" 根节点 ",
    loader:loader});
    var tree=new Ext.tree.TreePanel({
    renderTo:"hello",
    root:root,
    100
    });
    });

    首先我们使用 Ext.tree.TreeLoader 来初始化了一个 TreeLoader 对象,构造函数中的配 置
    参数 url 表示获得树节点信息的 url 。然后在初始化根节点的时候我们使用的是
    AsyncTreeNode ,在该节点中指定该节点的 laoder 为前面定义的 loader 。执行这段程序,在
    点击 “ 根节点 ” 时,会从服务器端指定 root 节点的子节点信息。
    TreeLoader 严格来说是针对树的节点来定义的,可以给树中的每一个节点定义不同的
    TreeLoader ,默认情况下,如果一个 AsyncTreeNode 节点在准备加载子节点的时候,如果 该
    节点上没有定义 loader ,则会使用 TreePanel 中定义的 loader 作为加载器。因此,我们可以
    直接在 TreePanel 上面指定 loader 属性,这样就不需要给每一个节点指定具体的 TreeLoader
    了。因此,上面的代码可以改成如下所示的内容 :

    9.4  自定义 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,
    '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:"http://www.cnblogs.com/liu2008hz/admin/'/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 来获得 jso n
    数据。
    WebInvokeTreeLoader 是自定义的树加载器,代码其实比较简单,你可以自己写一个。 本
    方案仅供参考,关于 WebInvokeTreeLoader 的源代码我已经传到了我用 ExtJS 开发的 Blog
    示例网站上了,仅供 VIP 会员浏览,有兴趣的朋友可跟我联系。

  • 相关阅读:
    poj 2763 Housewife Wind
    hdu 3966 Aragorn's Story
    poj 1655 Balancing Act 求树的重心
    有上下界的网络流问题
    URAL 1277 Cops and Thieves 最小割 无向图点带权点连通度
    ZOJ 2532 Internship 网络流求关键边
    ZOJ 2760 How Many Shortest Path 最大流+floyd求最短路
    SGU 438 The Glorious Karlutka River =) 拆点+动态流+最大流
    怎么样仿写已知网址的网页?
    5-10 公路村村通 (30分)
  • 原文地址:https://www.cnblogs.com/liu2008hz/p/1862702.html
Copyright © 2011-2022 走看看