(更新版)ExtJS Tree利用json(直接传List TreeNode,不需要转化为JSONArray)在Struts 2实现Ajax动态加载树结点

这次能改进,我得感谢一个人--斌哥。他也是刚开始学JavaScript,加我QQ,我们是这样认识的。parentId node 属性都是他创造的,也是动态异步加载的关键部分之一。这次的改进,我个人认为这应该是动态加载最简洁的做法。如有其它,还望高人指教,advance in thanks!

 

定义动态树的结点类 TreeNode.java

切记 该类的属性名称大部分 要和 Ext.tree.AsyncTreeNode或者Ext.tree.Node 的 Properties和Config Options一一对应,这样会自动导入到 Node 的属性中 ,这功能好迷人哦!但也可以传一些自己程序中要用的变量(如state,详见下文)。

每个属性的具体含义请参考ExtJSAPI Documentation ,官方网址:http://www.extjs.com/

public class TreeNode {

    private String id;// The node id
   
    // 新增属性,这是实现动态异步加载的关键属性(09.10.31尝试后发现不用parentId也可以实现动态异步加载)
    // private String parentId;// The parent node id

    
    private int state;// 自己程序中用到的参数,具体怎么访问请参见下面的 treeNav.js
   
    private String text;

//    private List<TreeNode> children = new ArrayList<TreeNode>(); // 该属性不能实现异步加载
   
    private String qtip;
    
    private String icon;
   
    private Boolean leaf;
    
    private Boolean expanded;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
    其它属性的 getter 和 setter 方法省略......
}

这个类没有实现序列化,但也可以序列化。两者的内在不同有待深究。

序列化代码如下所示,其它不变:

import java.io.Serializable;
public class TreeNode implements Serializable {
    private static final long serialVersionUID = 7261712903068621559L;

 

ApplyFormAction .java

想实践 Struts 2 结合 Spring 实现项目的朋友,强烈推荐《Struts 2 In Action 》(我也是第一次读 英文版 ,很容易理解,电子书PDF网上有下载),内容很全。官方网址:http://struts.apache.org/

package cn.hdu.action.admin;

import java.util.ArrayList;
import java.util.List;

import cn.hdu.domain.admin.*;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

import cn.hdu.service.admin.*;

@SuppressWarnings("serial")
public class ApplyFormAction extends ActionSupport{
    // 当单击节点并触发Action时,都会将节点的id加载到参数中,而node一方面保存id,另一方面又是父节点id,服务于" treeNode.setParentId(node ); "
    private String node;

     private List<TreeNode > treeNodes;
    /**
     * 只加载下一层节点信息
     */
    public String bindAsTree()
    {
        results = applyFormService.findAll();
       
        if(results != null) {
            treeNodes = new ArrayList<AdminTreeNode>();
           
            AdminTreeNode treeNode;
            for(final ApplyForm af: results) {
                treeNode = new AdminTreeNode();
                treeNode.setId(af.getFormId().toString());
                treeNode.setParentId(node );
                treeNode.setText(af.getShortName());
                treeNode.setState(af.getState());
                treeNode.setQtip(af.getFormName());
                treeNode.setIcon("images/icoImage/tree+.gif");
                treeNode.setLeaf(false);
                treeNodes.add(treeNode);
            }

            /* 首先,我 能做出这个要感谢先行者的付出才使我更向前一步!我这个的优势:不需要经过下面的转化,更不用将 nodesString 先输出到 JSP 页面上,然后 JavaScript 在读取它。这样就减省了这些不必要的转化时间,优势有没有自己衡量吧 ^-^
            JSONArray jsonObject = JSONArray.fromObject(treeNodes);
            try {
                nodesString = jsonObject.toString();
            } catch(Exception e) {
                nodesString = "ss";
            }
            */
        }
       
        return SUCCESS;
    }

    public String getNode() {
        return node;
    }

    public void setNode(String node) {
        this.node = node;
    }

     public List<TreeNode> getTreeNodes() {
        return treeNodes;
    }

    public void setTreeNodes(List<TreeNode> treeNodes) {
        this.treeNodes = treeNodes;
    }


}

 

 

struts.xml

因为用到了 extends ="json-default" ,所以要导入 jsonplugin-0.30.jar

想了解更多关于 Struts 2 的 JSON 插件的朋友,不妨进入 http://cwiki.apache.org/S2PLUGINS/json-plugin.html

<param name="root ">中的 root 设置是实现该功能成功的关键点之一。

<action name="bindAsTree" class="cn.hdu.action.admin.ApplyFormAction" method="bindAsTree">
                <result type="json">
                    <param name="root ">  <!-- 这里的name属性值一定要为 root,
Use the "root" attribute(OGNL expression) to specify the root object to be serialized(刚开始没成功可能是 TreeNode 序列化 引起的!若这里不设置root,则将 TreeNode 类先序列化 ,应该也可以成功,没试过。) . The parameter "root" should point to the getter property of the action object which contains the object to convert to JSON string data.    -->
                        treeNodes <!-- 一定要和
ApplyFormAction .java 中的红色标记 treeNodes 变量相同。不一定要这样,只要有getTreeNodes,变量名可以是其它,可以参考Spring的Getter和Setter实现原理。 -->
                    </param>
                </result>

        
</ action >
</ package >

 

 

表现层

treeNav.js

利用 ExtJS 作为开发工具的朋友,一定要充分利用其官方网站:http://www.extjs.com/ 。上面不但提供了各控件的不同功能实现的实例(可视化)和源代码(Firefox浏览器的Firebug调试插件可以得到所有的源码,好好利用吧),但可惜都不是动态的。还有就是非常详细的 API Documentation,这是开发人员的首选参考资料, 可以在其官方网址:http://www.extjs.com/ 下载到。

Ext.onReady(function(){
    Ext.BLANK_IMAGE_URL = 'ext-2.0.2/resources/images/default/s.gif';
    Ext.QuickTips.init();
 
    // set the root
  var root = new Ext.tree.AsyncTreeNode( {
    text : '根结点',
    draggable : false,
    id : '-100'
  });

   var tree = new Ext.tree.TreePanel( {
     rootVisible: false,
//     height: 500,
     margins: '5 5 4 5',
     autoScroll: true,
//     el: 'tree',
     renderTo: 'tree ',    // Using this config, a call to render() is not required (在html中存在一个 id 为 tree 的结点)
     animate: true,
     enableDD: false,
     title: '计划体系分类',
     root: root,    // You must define the root variable before when you set the root config
     loader: new Ext.tree.TreeLoader({
       dataUrl : 'admin/bindAsTree.action'
     }),
     listeners: {
             beforeclick: function(node, e) {
                     if(node.id[0] != 'r') {
                         if(node.attributes.state == 2) { // You can use this property to access any custom attributes you supplied (你可以通过
attributes 这个 属性获得任何你提供的属性值 )
                             jumpToApplyFrame(parseInt(node.id));
                         } else if(node.attributes.state == 1) {
                             Ext.Msg.alert('友情提示','此类项目申报尚在建设中。。。请关注!',function(){});
                         } else if(node.attributes.state == 3) {
                             Ext.Msg.alert('友情提示','此类项目申报已暂停使用!',function(){});
                         }
                     }
                 },
                 click:  function(node, e) {
                     if(node.isLeaf()) {
                        
                     } else {
                         // This node is expanded when it is not leaf node
                         node.toggle();
                     }
                 }
           }
   });

//   tree.setRootNode(root);
//   tree.render('tree');
   root.expand();
});

function jumpToApplyFrame(formId)
{
    var formIdType = document.getElementById('formIdType');
    var paraForm = document.getElementById('id_treePara');
    formIdType.value = formId;
    paraForm.submit();
}

 

最后,只要在相应的 html 文件中有如下代码即可:

<div id="tree"></div>

大功告成!

 

小结:

在STRUTS中使用EXTJS中的TREE实现异步加载树节点 http://www.blogjava.net/aoneany/articles/193537.html 这篇的 struts.xml 的 params="root "最为关键,那是最容易显示不了效果的地方,参见上文的 xml 文件即可。这是个牛人啊,崇拜!

 

还有一点教训 ,希望对后来者有用:

(1) 我在设置 TreeNode 的 id 属性时,将一些结点的 id 属性设置相同。这导致只有其中一个结点可用,其它的被自动屏蔽为不可用

 

(2)关于s.gif 文件的问题
     
       该问题会在系统不连互联网的情况下暴露。
     
       因为ExtJS在生成Tree时,默认情况下,总是访问http://extjs.com/s.gif下载这个s.gif图片文件。
 
       在不连网的情况下,树节点的导航图片显示不出,通过右键属性可知,是http://extjs.com/s.gif。
 
       通过搜索,发现该s.gif是在ext-base.js这个文件中定义的:
   
       BLANK_IMAGE_URL:"http:/"+"/extjs.com/s.gif"
 
       并且ExtJS中的示例程序是带有这个s.gif图片文件的。     
 
       根据具体应用情况,把ext-base.js修改成为:
 
       BLANK_IMAGE_URL:"../images/default/s.gif"
 
       或在mytree.js 文件开头加入如下语句:Ext.BLANK_IMAGE_URL="../images/default/s.gif"; 建议这么做。

 

Ext.BLANK_IMAGE_URL needs to be better for the end developer

 Ext.BLANK_IMAGE_URL=Ext.isIE6||Ext.isIE7||Ext.isAir? "resources/images/default/s.gif" : "data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";

 

2009年9月2日,本人碰到的问题 。如果对 s.gif 的引用路径不正确(即不能加载该图片),会导致树的树形导航线不能显示,忘朋友们注意。
 
 
(3) 调试的时候,JS报错:未结束的字符串常量。
 
      这个问题是因为JS调用时没有指定字符集,造成JS里的汉字出现乱码引起的。
 
      调用JS时,可以指定使用字符集。
 
      如:<script type="text/javascript" defer=true src="xxx.js" charset="utf-8">

 

 

 

版权声明:

如果大家要转载本文,我非常荣幸。但请参加转载网址,谢谢!

 

你可能感兴趣的:(JavaScript,Ajax,json,struts,ext)