關於一個tree的寫法的記錄

1.      首先還是主要的顯示頁面tree.html,這裏有兩個地方要注意一下,一個是我們引用的JS如果採用GBK的默認編碼,瀏覽器會顯示未結束的字符串常量的錯誤,所以我們一般會修改JS文件的編碼方式爲UTF-8,或者在導入JS時加上編碼字符集。第二個是我們要定義一個顯示TreePanelDIV

 

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

<link rel="stylesheet" type="text/css" href="resources/css/ext-all.css" />

<script type="text/javascript" src="resources/js/ext-base.js"></script>

<script type="text/javascript" src="resources/js/ext-all.js"></script>

<script type="text/javascript" src="resources/js/tree.js" charset="gbk"></script>

</head>

<body>

<div id="tree-panel" style="overflow:auto; height:300px;width:200px;border:2px solid #c3daf9;"></div>

</body>

</html>

 

2.      然後是我們的主體JS文件,tree.js,爲了凸顯主題,這個我已經做了必要的簡化,還做了詳細的註釋,大家好好看一下。

 

Ext.onReady(function() {

    Ext.QuickTips.init();// 浮動信息提示

    Ext.BLANK_IMAGE_URL = 'resources/images/default/s.gif';// 替換圖片文件地址爲本地

 

    // 創建一個簡寫

    var Tree = Ext.tree;

    // 定義根節點的Loader

    var treeloader = new Tree.TreeLoader({

            // dataUrl : 'tree.jsp'//這裏可以不需要指定URL,在加載前事件響應裏面設置

            });

 

    // 添加一個樹形面板

    var treepanel = new Tree.TreePanel({

        // renderTo:"tree_div",//如果使用renderTo,則不能使用setRootNode()方法,需要在TreePanel中設置root屬性。

        el : 'tree-panel',// 將樹形添加到一個指定的div,非常重要!

        region : 'west',

        title : '功能菜單',

        width : 200,

        minSize : 180,

        maxSize : 250,

        split : true,

        autoHeight : false,

        frame : true,// 美化界面

        // width : 200,//面板寬度

        // title : '可編輯和拖動的異步樹',//標題

        // autoScroll : true, // 自動滾動

        enableDD : true,// 是否支持拖拽效果

        containerScroll : true,// 是否支持滾動條

        rootVisible : true// 是否隱藏根節點,很多情況下,我們選擇隱藏根節點增加美觀性

        border : true// 邊框

        animate : true// 動畫效果

        loader : treeloader

            // 樹加載

        });

    // 異步加載根節點

    var rootnode = new Tree.AsyncTreeNode({

                id : '0',

                text : '家電品牌總類',

                draggable : false,// 根節點不容許拖動

                expanded : true

            });

 

    // tree設置根節點

    treepanel.setRootNode(rootnode);

 

    // 響應加載前事件,傳遞node參數

    treepanel.on('beforeload'function(node) {

                treepanel.loader.dataUrl = 'tree.jsp?parentId=' + node.id; // 定義子節點的Loader

            });

    // 渲染樹形

    treepanel.render();

    // 展開節點,第一個參數表示是否級聯展開子節點

    rootnode.expand(true);

 

    // 設置樹的點擊事件

    function treeClick(node, e) {

        if (node.isLeaf()) {

            e.stopEvent();

            var n = contentPanel.getComponent(node.id);

            if (!n) {

                var n = contentPanel.add({

                            'id' : node.id,

                            'title' : node.text,

                            closable : true,

                            autoLoad : {

                                url : 'tabFrame.jsp?url=grid.html',

                                scripts : true

                            // 通過autoLoad屬性載入目標頁,如果要用到腳本,必須加上scripts屬性

                        });

            }

            contentPanel.setActiveTab(n);

        }

    }

    // 增加鼠標單擊事件

    treepanel.on('click', treeClick);

 

    // 定義右鍵菜單

    var rightClick = new Ext.menu.Menu({

                id : 'rightClickCont',

                items : [{

                            id : 'rMenu1',

                            text : '添加節點',

                            // 增加菜單點擊事件

                            handler : function() {

                                alert('添加節點的實現!');

                            }

                        }, {

                            id : 'rMenu2',

                            text : '編輯節點'

                        }, {

                            id : 'rMenu3',

                            text : '刪除節點'

                        }]

            });

    // 增加右鍵點擊事件

    treepanel.on('contextmenu'function(node, event) {// 聲明菜單類型

                event.preventDefault();// 阻止瀏覽器默認右鍵菜單顯示

                rightClick.showAt(event.getXY());// 取得鼠標點擊座標,展示菜單

            });

 

    /*

     設置tree的節點放置函數此函數有一個很重要的參數對象e e對象有三個重要的屬性,分別爲dropNode,target,point

     * 1.dropNode爲在拖動時鼠標抓住的節點 2.target爲將要放置在某處的節點

     * 3.point爲被放置的狀態,分別有append表示添加,above節點的上方,below節點的下方。

     *

     */

    treepanel.on('nodedrop'function(e) {

 

                if (e.point == 'append') {

                    alert('當前"' + e.dropNode.text + '"劃到"' + e.target.text

                            '"裏面!');

                else if (e.point == 'above') {

                    alert('當前"' + e.dropNode.text + '"放在了"' + e.target.text

                            '"上面!');

                else if (e.point == 'below') {

                    alert('當前"' + e.dropNode.text + '"放在了"' + e.target.text

                            '"下面!');

                }

            });

 

    // 在原有的樹形添加一個TreeEditor

    var treeEditer = new Tree.TreeEditor(treepanel, {

                allowBlank : false

            });

    /*

     爲創建的treeEditer添加事件 有兩個事件最爲常用,一個爲beforestartedit另一個爲complete

     從名字就可以看出,beforestartedit事件是在編輯前的事件,因此可以通過它來判斷那些節點可以編輯那些不可以。

     * complete爲編輯之後的事件,在這裏面可以添加很多事件,比如添加一個Ext.Ajax向後臺傳送修改的值等等。

     */

    treeEditer.on("beforestartedit"function(treeEditer) {

                var tempNode = treeEditer.editNode;// 將要編輯的節點

                if (tempNode.isLeaf()) {// 這裏設定葉子節點才容許編輯

                    return true;

                else {

                    return false;

                }

            });

 

    treeEditer.on("complete"function(treeEditer) {

                alert("被修改爲" + treeEditer.editNode.text);

            });

 

    // 1)通過TabPanel控件的html屬性配合<iframe>實現。該方法是利用

    // html屬性中包含<iframe>的語法來調用另一個頁面,具體見代碼。

    // 2)通過TabPanel控件的autoLoad屬性實現。該方法是利用autoLoad屬性,它有很多參數,

    // 其中有兩個比較重要,url表示要載入的文件,scripts表示載入的文件是否含有腳本,該屬性相當重要,

    // 如果在新的頁面中要創建Ext控件,必須指定該參數。該方法實現較前一個複雜,因爲引入的文件不是一個完整的html文件,

    // 有可能只是內容的一部分,但是資源佔用較少,而且載入速度較快(它有一個載入指示)

 

    // 添加第一個節點(html)

    treepanel.root.appendChild(new Ext.tree.TreeNode({

        id : 'htmlPanel',

        text : '通過html打開',

        listeners : {

            'click' : function(node, event) {

                event.stopEvent();

                var n = contentPanel.getComponent(node.id);

                if (!n) { // 判斷是否已經打開該面板

                    n = contentPanel.add({

                        'id' : node.id,

                        'title' : node.text,

                        closable : true// 通過html載入目標頁

                        html : '<iframe scrolling="auto" frameborder="0" width="100%" height="100%" src="grid.html"></iframe>'

                    });

                }

                contentPanel.setActiveTab(n);

            }

        }

    }));

 

    // 添加第二個節點(autoLoad)

    treepanel.root.appendChild(new Ext.tree.TreeNode({

                id : 'autoLoadPanel',

                text : '通過autoLoad打開',

                listeners : {

                    'click' : function(node, event) {

                        event.stopEvent();

                        var n = contentPanel.getComponent(node.id);

                        if (!n) { // //判斷是否已經打開該面板

                            n = contentPanel.add({

                                        'id' : node.id,

                                        'title' : node.text,

                                        closable : true,

                                        autoLoad : {

                                            url : 'tabFrame.jsp?url=grid.html',

                                            scripts : true

                                        // 通過autoLoad屬性載入目標頁,如果要用到腳本,必須加上scripts屬性

                                    });

                        }

                        contentPanel.setActiveTab(n);

                    }

                }

            }));

 

    // 右邊具體功能面板區

    var contentPanel = new Ext.TabPanel({

        region : 'center',

        enableTabScroll : true,

        activeTab : 0,

        items : [{

            id : 'homePage',

            title : '首頁',

            autoScroll : true,

            html : '<div style="position:absolute;color:#ff0000;top:40%;left:40%;">Tree控件和TabPanel控件結合功能演示</div>'

        }]

    });

 

    new Ext.Viewport({

                layout : 'border'// 使用border佈局

                defaults : {

                    activeItem : 0

                },

                items : [treepanel, contentPanel]

            });

 

});

 

3.   再接着是tree.jsExtJSTreeLoader調用的tree.jsp,在目錄樹上點擊TreeNode後會加載下一級節點。tree.jsp負責TreeNode點擊後,傳回由下一級節點構造的JSON數據,也就是前臺樹異步請求訪問的後臺WEB組件。它會調用JAVABEAN操作數據庫,得到每個節點的子節點數據。這裏由於我們後臺需要返回給客戶端JSON格式的數據,也就是需要操作JSON數據格式。所以我們首先要下載JSON-lib,地址:http://json-lib.sourceforge.net/打開網址後,首頁上有一段話: 
 Json-lib requires (at least) the following dependencies in your classpath: 
      jakarta commons-lang 2.3 
      jakarta commons-beanutils 1.7.0 
      jakarta commons-collections 3.2 
      jakarta commons-logging 1.1.1 
      ezmorph 1.0.4 
   
需要下載上述jar文件,配合JSON-lib 一起使用。
 
   commons 
下載地址:http://commons.apache.org/ 
   ezmorph 
下載地址:
http://ezmorph.sourceforge.net 
   
或者,到 http://www.docjar.com 搜索下載。
 
   JSON
的用法,我們已經提過多次,大家可參考相關文檔。看看tree.jsp的代碼:

 

<%@ page language="java" pageEncoding="utf-8"%>

<jsp:useBean class="org.leno.javabean.JSONTree" id="JSONTree"></jsp:useBean>

<%

    String parentId = "";

    if (request.getParameter("parentId") != null) {

        parentId = request.getParameter("parentId").toString();

    }

    JSONTree.setparentId(parentId);

%>

<%=JSONTree.getJSONString()%>

 

4.       後臺用到的JAVA,這裏包括訪問數據庫的數據源工廠類DataSourceFactory(這裏用到了DBCP連接池,大家要記得導入連接sqlserver 2000數據庫和dbcp連接池的相關JAR包!),定義樹節點的屬性,包括節點IDText、圖標、是否爲葉子節點、是否展開等的類JSONTreeNode,還有類似DAO能夠封裝數據訪問和格式轉換細節的JSONTree

 

package org.leno.javabean;

 

import java.sql.SQLException;

import org.apache.commons.dbcp.BasicDataSource;

 

public class DataSourceFactory {

 

    /**

     * @param args

     */

    private static BasicDataSource ds;

 

    public static BasicDataSource getDataSource() {

        if (ds == null) {

            ds = new BasicDataSource();

            ds.setDriverClassName("com.microsoft.jdbc.sqlserver.SQLServerDriver");

            ds.setUrl("jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=java28");

            ds.setUsername("sa");

            ds.setPassword("123");

            ds.setMaxActive(5);

        }

        return ds;

 

    }

 

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        try {

            System.out.println(DataSourceFactory.getDataSource()

                    .getConnection());

        catch (SQLException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

 

    }

 

}

package org.leno.javabean;

 

/**

 * @author leno

 *定義樹節點的屬性,包括節點IDText、圖標、是否爲葉子節點、是否展開等。

 */

public class JSONTreeNode {

 

        private String id;            //ID

         private String text;          //節點顯示

         private String cls;           //圖標

         private boolean leaf;         //是否葉子

         private String href;          //鏈接

         private String hrefTarget;    //鏈接指向

         private boolean expandable;   //是否展開

         private String description;   //描述信息

        

        get/set……

}

package org.leno.javabean;

 

import java.sql.*;

import java.util.*;

import net.sf.json.JSONArray;

 

public class JSONTree {

private String parentId;

   

    public String getJSONString(){     

        Connection con =null;

        Statement st = null;

        ResultSet rs = null;

        List<JSONTreeNode> treeNodeArray = null;

       

        String SQLString = "SELECT * FROM Categories WHERE parentId="+this.parentId+" ORDER BY categoryId";   

           

        try

        {

            con = DataSourceFactory.getDataSource().getConnection();

            st = con.createStatement();

            //查找所有擁有下級類別的類別ID

            rs = st.executeQuery("SELECT parentId FROM Categories WHERE parentId>0 Group By parentId Order By parentId");           

           

            StringBuffer parentIDBuffer =new StringBuffer();

            parentIDBuffer.append("|");        

            while(rs.next())

            {

                parentIDBuffer.append(rs.getString("parentId"));

                parentIDBuffer.append("|");

            }

            //得到所有的parentcategoryId列表

            String parentIDString = parentIDBuffer.toString();        

           

            rs = st.executeQuery(SQLString);   

            treeNodeArray = new ArrayList<JSONTreeNode>();

            while(rs.next())

            {

                JSONTreeNode treeNode = new JSONTreeNode();

                String categoryId = rs.getString("categoryId");

                treeNode.setId(categoryId);

                treeNode.setText(rs.getString("categoryName"));

                treeNode.setDescription(rs.getString("description"));         

//                    treeNode.setHref("rightframe.jsp?categoryId="

//                      + rs.getString("categoryId").toString());

//                    treeNode.setHrefTarget("rightFrame");              

               

                if (parentIDString.indexOf("|"+categoryId+"|")>=0) //父節點

                    {

                        treeNode.setCls("folder");

                        treeNode.setLeaf(false);

                        treeNode.setExpandable(false);

                    }

                    else //子節點

                   {

                        treeNode.setCls("file");

                        treeNode.setLeaf(true);

                        treeNode.setExpandable(false);

                    }

                    treeNodeArray.add(treeNode);

            }

           

            JSONArray JsonArray = JSONArray.fromObject(treeNodeArray); //得到JSON數組    

 

            return JsonArray.toString();//返回JSON數據

        }

        catch(Exception e)

        {

            System.out.println("getJSONString() of JSONTree.java throws : "+e.toString());

            return "";

        }

        finally

        {

           try {

           if(con!=null&&!con.isClosed()){

                con.close();

           }

        catch (SQLException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        }

    }  

 

 

    public String getparentId() {

        return parentId;

    }

 

    public void setparentId(String parentId) {

        this.parentId = parentId;

    }

 

}

 

5.      最後是我們的數據庫腳本script.sql,大家用SQLServer 2000數據庫創建一個java28database,然後執行下列腳本即可。

 

create table Categories

(

    categoryId int identity(1,1) primary key,

    categoryName varchar(30),

    description varchar(100),

    parentId int

)

insert into Categories values('電腦','關於電腦',0);

insert into Categories values('電視機','關於電視機',0);

insert into Categories values('數碼相機','關於數碼相機',0);

insert into Categories values('冰箱','關於冰箱',0);

insert into Categories values('聯想電腦','關於聯想電腦',1);

insert into Categories values('創維電視機','關於創維電視機',2);

insert into Categories values('索尼相機','關於索尼相機',3);

insert into Categories values('海爾冰箱','關於海爾冰箱',4);

 

insert into Categories values('旭日電腦','關於旭日電腦',5);

insert into Categories values('天逸電腦','關於天逸電腦',5);

insert into Categories values('創維液晶電視','關於創維液晶電視機',6);

insert into Categories values('索尼M23相機','關於索尼M23相機',7);

insert into Categories values('海爾G1冰箱','關於海爾G1冰箱',8);

 

select * from Categories

SELECT parentId FROM Categories WHERE parentId>0 Group By parentId Order By parentId

 

可能有人對ExtJS中樹的節點屬性不是很瞭解,所以我們要囉嗦一下。ExtJS只要求返回的數據格式類似下面這樣即可:
[{'text':'welcome.html','id':'welcome.html','cls':'file',myPara:'myValue'},
{'text':'welcome2.html','id':'welcome2.html','leaf':true,'cls':'file','href':'welcome2.html'}]
這些數據是存儲到一個數組中的,數組中的每一項代表一個節點,每一個節點都包含以下幾個主要屬性
:
text:
定義該節點顯示的名稱
;
id:
定義該節點的頁面ID,便於document.getElementById方法獲取該節點
;
leaf:true
或者false,定義該節點是否是葉子節點
;
cls:
定義該節點的class(顯示的樣式
);
href:
定義點擊該節點後鏈接的頁面
;
另外你還可以爲節點增加自定義的屬性,方法如上面的myPara:'myValue'一樣。ExtJS會自動將返回的數據解析成節點並正確顯示到頁面上。

 

好啦,今天我們TreePanel的學習就到這裏,下次我們會學習FormPanel。祝願大家學有所成。

發佈了22 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章