这次我们来学习下ExtJS中的树面板(TreePanel),很多人都说,只是为了树,都要好好学习ExtJS!可见大家对Tree的一往情深。从另一方面来说,Tree这种结构在实际项目中也的确用得相当广泛,所以我们很有必要研究一下它。这次我们完成的树大致上有这样的功能:它的节点是动态异步从后台(存储在数据库中一张电子产品分类表)加载的,节点之间可以拖曳,节点可以编辑,同时还支持右键菜单,而且,它能够和TabPanel结合构成经典的布局方式。呵呵,是不是很强大?!大家已经看到,我们组件的讲解是逐步递推的,所以我们这里也会用到刚学过的GridPanelTabPanel这些实用的面板。我们看效果先:

好啦,洪哥,我们动手吧!

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。祝愿大家学有所成。

转载于:https://www.cnblogs.com/CharmingDang/archive/2008/10/19/9663751.html

ExtJS专题-TreePanel(1)相关推荐

  1. Extjs Ext.TreePanel

    TreePanel 简单实例. <link rel="stylesheet" href="Js/ext-4.2/resources/css/ext-all-nept ...

  2. JavaScriptSerializer序列化和反序列化JSON:使用自定义JavaScriptConverter

    JSON的序列化和反序列化已经成为Web开发必不可少的知识.现在常用的有System.Web.Script.Serialization下的JavaScriptSerializer来进行处理:另外一个比 ...

  3. 73. 解决ExtJS TreePanel 的 iconCls设置问题

    转自:https://blog.csdn.net/hanchuang213/article/details/62881568 很久没有写代码了,最近在做一个在线帮助网站,于是又捡起了 ExtJS,我用 ...

  4. ExtJs TreePanel 不能加载ashx数据的解决办法

    今天学习Extjs TreePanel 时在加载动态数据时经常加载不进来,因为我是使用MVC2获取动态数据的,单独调试MVC的返回数据时OK的,网上有很多解决方案,其中最简单的是: loader: n ...

  5. 关于ExtJS通过单击左边的treePanel在居中的panel加载页面问题

    2019独角兽企业重金招聘Python工程师标准>>> 这几天整ExtJS通过单击treePanel在居中的panel加载页面问题.第一次加载的页面正常显示在panel中,但是从第二 ...

  6. extjs给panel添加滚动条_extjs.treePanel在ie9下滚动条的显示问题-阿里云开发者社区...

    新接手的项目前端用的是extjs.在ie9下有一个treepanel的下拉滚动条死活出不来.后来把树的定义改成了这样:var multiSelectTree = new Ext.tree.TreePa ...

  7. Extjs 实战之 Ext.tree.TreePanel Tree无法显示

    这里使用的是 Ext.ux.tree.ColumnTree, 这是一个TreePanel的扩展类, 从Extjs下载的官方包里就包含了这个. 1. 问题描述: tree 的头部显示正常, 数据部分在F ...

  8. ExtJs TreePanel使用TreeLoader在IE下无法正常加载显示的解决方法

    小菜使用如下代码生成TreePanel,代码与ExtJs自带的examples类似,在Firefox下运行正常,不过在IE下无法正常显示. Code <script language=" ...

  9. cls extjs5_73. 解决ExtJS TreePanel 的 iconCls设置问题

    转自:https://blog.csdn.net/hanchuang213/article/details/62881568 很久没有写代码了,最近在做一个在线帮助网站,于是又捡起了 ExtJS,我用 ...

最新文章

  1. 阿里云数据库POLARDB技术沙龙火热报名中,李飞飞,曹伟 众大神齐到场,200个席位先到先得!...
  2. php 多维数组怎么去重,php多维数组去重,该如何解决
  3. 极乐科技CEO应邀出席2017微信小程序生态课
  4. VB6调用API打开目标文件所在文件夹且选中目标文件
  5. 消息驱动 微服务器,消息驱动的微服务-Spring Cloud Stream整合RocketMQ
  6. JS数据结构与算法——选择排序(把小的数字依次往前放)
  7. qt5 linux apt get,Ubuntu 14.04下安装并配置Qt5.7.0
  8. Spring Boot 知识笔记(集成zookeeper)
  9. untiy对过相机参数计算视场角
  10. QCA9531方案双通道嵌入式无线AP模块应用选型参考
  11. ESP8266 wifi模块代码详解
  12. 如何使用plink进行二分类性状的GWAS分析并计算PRS得分
  13. 智能卡卡发卡流程(收藏1)
  14. chatGPT 与文言一心的对比
  15. 申论范文:共同富裕“一定”会考的点
  16. 华为笔记本换装linux双系统,matebook的win+ubuntu双系统安装方法
  17. c语言实现顺序存储程序,线性表的顺序存储结构动态态分配C语言实现
  18. 吴国忠先生谈郑曼青太极拳之思路
  19. 【BZOJ3669】【NOI2014】魔法森林 (spfa动态队列加点算法)
  20. Oracle应用之merge合并更新函数

热门文章

  1. yield方法释放锁吗_死磕Synchronized底层实现重量级锁
  2. java三元操作符注意
  3. 操作系统上机作业--根据莱布尼兹级数计算PI(1)(多线程)
  4. Windows Hook(2)调用DLL函数
  5. 《MySQL 8.0.22执行器源码分析(4.1)Item_sum类以及聚合》
  6. Java Collections list()方法与示例
  7. 递归函数python有什么特点_Python中的递归
  8. 刚刚有水了一道,用递归实现进制转换
  9. 【剑指offer】_16 构建乘积数组
  10. 设计模式----2(简单工厂模式的概念,简单工厂模式的实现,简单工厂模式的优缺点)