1.简单的树
效果图
代码
<script type="text/javascript" defer> Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = '<%=rootpath%>/ext/resources/images/default/s.gif'; var tree = new Ext.tree.TreePanel({ region: 'center', //True表示为面板是可收缩的,并自动渲染一个展开/收缩的轮换按钮在头部工具条 collapsible: true, title: '标题',//标题文本 width: 200, border : false,//表框 autoScroll: true,//自动滚动条 animate : true,//动画效果 rootVisible: true,//根节点是否可见 split: true, tbar:[{ text:'展开', handler:function(){ tree.expandAll(); } },'-',{ text:'折叠', handler:function(){ tree.collapseAll(); tree.root.expand(); } }], listeners: { click: function(node) { //得到node的text属性 Ext.Msg.alert('消息', '你点击了: "' + node.attributes.text+"'"); } } }); var root = new Ext.tree.TreeNode({text:'我是根'}); var root_node1 = new Ext.tree.TreeNode({text:'我是根的1枝'}); var root_node2 = new Ext.tree.TreeNode({text:'我是根的2枝'}); //插入节点为该节点的最后一个子节点 root.appendChild(root_node1); root.appendChild(root_node2); //设置根节点 tree.setRootNode(root); new Ext.Viewport({ items: [tree] }); }); </script>
2.使用TreeLoader获得后台数据
每个节点最后一级必须是叶子节点,否则会出现无限循环 TreeNode并不支持Ajax,需要把根节点换成AsyncTreeNode实现异步加载效果
list.txt
[{ text : '01', children : [ { text : '01-01' , leaf : true }, { text : '01-02' , leaf : true } ] },{ text :'02', children : [ { text : '02-01' , leaf : true }, { text : '02-02' , leaf : true } ] }]index.jsp
<script type="text/javascript" defer> Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = '<%=rootpath%>/ext/resources/images/default/s.gif'; var tree = new Ext.tree.TreePanel({ region: 'center', collapsible: true, title: 'TreeLoader获得后台数据', width: 200, border : false, autoScroll: true, animate : true, rootVisible: false, split: true, loader : new Ext.tree.TreeLoader({ dataUrl : 'list.txt' }), root: new Ext.tree.AsyncTreeNode({ //进入时是否展开 expanded:false, text:'根节点' }), listeners: { afterrender: function(node) { tree.expandAll();//展开树 } } }); new Ext.Viewport({ items: [tree] }); }); </script>3.读取本地JSON数据
因为有的树形的数据并不多,为了获得如此少量的数据而使用Ajax访问后台不划算, 如果退回到每个节点都使用new来生成,又实在太麻烦, 那么能不能让TreeLoader读取本地的JavaScript中的JSON数据,然后生成需要的树节点呢
<script type="text/javascript" defer> Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = '<%=rootpath%>/ext/resources/images/default/s.gif'; var tree = new Ext.tree.TreePanel({ region: 'center', //True表示为面板是可收缩的,并自动渲染一个展开/收缩的轮换按钮在头部工具条 collapsible: true, title: '标题',//标题文本 width: 200, border : false,//表框 autoScroll: true,//自动滚动条 animate : true,//动画效果 rootVisible: false,//根节点是否可见 split: true, loader : new Ext.tree.TreeLoader(), root : new Ext.tree.AsyncTreeNode({ text:'我是根', children:[{ text : '01', children : [ { text : '01-01' , leaf : true }, { text : '01-02' , leaf : true } ] },{ text :'02', children : [ { text : '02-01' , leaf : true }, { text : '02-02' , leaf : true } ] }] }), listeners: { afterrender: function(node) { tree.expandAll();//展开树 } } }); new Ext.Viewport({ items: [tree] }); }); </script>4.使用JSP提供后台数据
树形异步读取的关键是node参数,当某一个节点展开时,treeLoader会根据设置的dataUrl去后台读取数据, 而发送请求时,treeLoader会把这个节点的Id作为参数一起发送到后台,对于后台来说,只要获取node参数, 就知道是哪个节点正在执行展开, 如果返回的子节点数据包含leaf:true属性,AsyncTreeNode就会生成TreeNode节点,并标记为叶子
list.jsp
<%@ page language="java" pageEncoding="UTF-8"%> <% request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); //获取node参数,对应的是正在展开的节点id String node = request.getParameter("node"); System.out.println("node="+node); String json = "["+ "{id:1,text:'01',"+ "children:["+ "{id:11,text:'01-01',leaf:true},"+ "{id:12,text:'01-02',leaf:true}"+ "]}"+ ",{id:2,text:'02',"+ "children:["+ "{id:21,text:'02-01',leaf:true},"+ "{id:22,text:'02-02',leaf:true}"+ "]}"+ "]"; response.getWriter().write(json); %>
index.jsp
<script type="text/javascript" defer> Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = '<%=rootpath%>/ext/resources/images/default/s.gif'; var tree = new Ext.tree.TreePanel({ region: 'center', collapsible: true, title: '标题', width: 200, border : false, autoScroll: true, animate : true, rootVisible: false, split: true, loader : new Ext.tree.TreeLoader({ dataUrl : 'list.jsp' }), root : new Ext.tree.AsyncTreeNode({ //设置id,让后台知道应该在何时返回根节点的子点数据 id : '0', text : '我是根' }), listeners: { afterrender: function(node) { tree.expandAll();//展开树 } } }); new Ext.Viewport({ items: [tree] }); }); </script>5.树的事件
listeners: { click: function(node) { Ext.Msg.alert('消息', '你点击了: "' + node.attributes.text); }, dblclick:function(node){ alert('你双击了'+node); }, expandnode:function(node){ alert(node+'展开了'+node.attributes.text); }, collapsenode:function(node){ alert(node+'折叠了'+node.attributes.text); } }
6.右边菜单
效果图
list.txt
[{ text : '01', children : [ { text : '01-01' , leaf : true }, { text : '01-02' , leaf : true } ] },{ text :'02', children : [ { text : '02-01' , leaf : true }, { text : '02-02' , leaf : true } ] }]index.jsp
<script type="text/javascript" defer> Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = '<%=rootpath%>/ext/resources/images/default/s.gif'; var node_id; var tree = new Ext.tree.TreePanel({ region: 'center', collapsible: true, title: '右键菜单', width: 200, border : false, animate : true, rootVisible: false, autoScroll: true, split: true, loader : new Ext.tree.TreeLoader({ dataUrl : 'list.txt' }), root: new Ext.tree.AsyncTreeNode({ //设置id,让后台知道应该在何时返回根节点的子点数据 id : '0', text : '我是根' }), listeners: { afterrender: function(node) { //展开树 tree.expandAll(); } } }); var cc = new Ext.menu.Menu({ items :[{ text: '增加', handler : function(){ alert(node_id.attributes.text); cc.hide();//隐藏 } },{ text: '删除', handler : function(){ alert('删除'); } },{ text: '修改', handler : function(){ alert('修改'); } }] }); tree.on('contextmenu',function(node,e){ e.preventDefault();//阻止浏览器默认弹出功能菜单 node.select();//选中当前节点 //var array = new Array(500,500);//可以自定义坐标 var array = e.getXY();//获取事件的页面坐标 cc.showAt(array);//在指定的位置显示该菜单 node_id = node; }); new Ext.Viewport({ items: [tree] }); }); </script>7.给树节点设置图片和超链接
list.txt
[{ text : '01', children : [ { text : '01-01' , leaf : true , icon : 'image/qq.jpg' }, { text : '01-02' , leaf : true , href : 'http://www.baidu.com' } ] },{ text :'02', children : [ { text : '02-01' , leaf : true }, { text : '02-02' , leaf : true } ] }]8.修改树节点的标题
list.txt
[{ text : '01', children : [ { text : '01-01' , leaf : true }, { text : '01-02' , leaf : true } ] },{ text :'02', children : [ { text : '02-01' , leaf : true }, { text : '02-02' , leaf : true } ] }]index.jsp
<script type="text/javascript" defer> Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = '<%=rootpath%>/ext/resources/images/default/s.gif'; var tree = new Ext.tree.TreePanel({ region: 'center', collapsible: true, title: '修改节点标题', width: 200, border : false, animate : true, rootVisible: false, autoScroll: true, split: true, loader : new Ext.tree.TreeLoader({ dataUrl : 'list.txt' }), root: new Ext.tree.AsyncTreeNode({ id : '0', text : '我是根' }), listeners: { afterrender: function(node) { //展开树 tree.expandAll(); } } }); //为树节点提供即时的编辑功能 var treeEditor = new Ext.tree.TreeEditor(tree,new Ext.form.TextField({ allowBlank : false })); /* 编辑器开始初始化,但在修改值之前触发, 若事件句柄返回false则取消整个编辑事件 editor : treeEditor本身 value : 正被设置的值 */ treeEditor.on('beforestartedit',function(editor,element,value){ var treeNode = editor.editNode; var boolean = treeNode.isLeaf(); return boolean; }); /* 完成修改后,按下Enter就会触发这个事件,我们可以监听函数得到修改后的数据 editor : treeEditor本身 value : 修改后的值 startValue : 改变后的值 */ treeEditor.on('complete',function(editor,value,startValue){ alert('将要设置的值: '+editor.editNode.text+' 原来的值: '+startValue+" 改变后的值: "+value) }); new Ext.Viewport({ items: [tree] }); }); </script>9.树的拖放
如果让树节点可以自由拖放,创建TreePanel时设置enableDD:true即可 不过直接设置只能实现叶子与枝干和根之间的拖放,叶子不能拖放到叶子下
list.txt
[{ text : '01', children : [ { text : '01-01' , leaf : true }, { text : '01-02' , leaf : true } ] },{ text :'02', children : [ { text : '02-01' , leaf : true }, { text : '02-02' , leaf : true } ] }]inde.jsp
<script type="text/javascript" defer> Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = '<%=rootpath%>/ext/resources/images/default/s.gif'; var tree = new Ext.tree.TreePanel({ region: 'center', collapsible: true, title: '树的拖动', width: 200, border : false, animate : true, rootVisible: false, autoScroll: true, split: true, enableDD : true,//支持拖放 loader : new Ext.tree.TreeLoader({ dataUrl : 'list.txt' }), root: new Ext.tree.AsyncTreeNode({ id : '0', text : '我是根' }), listeners: { afterrender: function(node) { //展开树 tree.expandAll(); } } }); new Ext.Viewport({ items: [tree] }); }); </script>9.1 节点拖放的三种形式
append 放下去节点会变成被砸中节点的子节点,形成父子关系,绿色加号标志 above 放下的节点与目标节点是兄弟关系,放下去的节点排列在前,一个箭头两个短横线 below 放下的节点与目标节点是兄弟关系,放下去的节点排列在后,两个短横线一个箭头
9.2叶子不能append
tree.on('nodedragover',function(e){ //获取事件的对象 var node = e.target;//当鼠标指针经过的节点 if(node.leaf){ n.leaf = false; } return true; });
9.3 判断拖放的目标
tree.on('nodedrop',function(e){ Ext.Msg.alert('消息','我们的节点 '+e.dropNode+' 掉到了 '+e.target+' 上,掉落方式是 '+ e.point); });
10.树的过滤器Ext.tree.TreeFilter
list.txt
[{ text : '01', children : [ { text : '01-01' , leaf : true }, { text : '01-02' , leaf : true } ] },{ text :'02', children : [ { text : '02-01' , leaf : true }, { text : '02-02' , leaf : true } ] }]index.jsp
<script type="text/javascript" defer> Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = '<%=rootpath%>/ext/resources/images/default/s.gif'; var tree = new Ext.tree.TreePanel({ region: 'center', collapsible: true, title: 'tree过滤器', width: 400, border : false, animate : true, rootVisible: false, autoScroll: true, split: true, loader : new Ext.tree.TreeLoader({ dataUrl : 'list.txt' }), root : new Ext.tree.AsyncTreeNode({ //设置id,让后台知道应该在何时返回根节点的子点数据 id : '0', text : '我是根' }), listeners: { afterrender: function(node) { //展开树 tree.expandAll(); } }, tbar:[{ text:'显示02', handler:function(){ treeFiler.filter('02');//通过指定的属性过滤数据 } },'-',{ text:'显示全部', handler:function(){ treeFiler.clear();//清理现在的过滤 } },'-',{ xtype : 'textfield', //为HTML的input输入字段激活键盘事件的代理 enableKeyEvents : true, listeners : { //这个事件只能在enableKeyEvents = true可用 keyup : function(e){ var t = this.getValue() /****************过滤时应该避开叶子节点**********************/ //传递的字符串参数被正则表达式读取 var es = Ext.escapeRe(t); var re = new RegExp(es,'i'); //通过一个函数过滤,函数返回true,那么该节点将保留 treeFiler.filterBy(function(n){ return !n.isLeaf() || re.test(n.text); }); /**********不匹配的叶子节点的父节点也隐藏**************/ hiddenPkgs =[]; //从该节点开始逐层下报(Bubbles up)节点,上报过程中对每个节点执行指定的函数 tree.root.cascade(function(n){ //当节点有子节点的时候n.ui.ctNode.offsetHeight大于3 if(!n.isLeaf()&&n.ui.ctNode.offsetHeight<3){ n.ui.hide(); hiddenPkgs.push(n); } }); } } }] }); var treeFiler = new Ext.tree.TreeFilter(tree,{ clearBlank : true,//如果查询的字符串为空字符串,就执行clear() //每次过滤之前先执行clear()负责会在上次过滤结果的基础上进行查询 autoClear : true }); new Ext.Viewport({ items: [tree] }); }); </script>11.利用TreeSorter对树进行排序
TreeSorter是一个专门用来对树节点进行排序的工具 caseSensitive 区分大小写,默认为false不区分大小写 dir 排列方式 folderSort 将叶子节点排列到非叶子节点后面 默认为false leafAttr 判断叶子节点的标志,默认为leaf,如果node中存在leaf:true参数,就认为是叶子节点 property 根据节点属性排序,默认为text
代码
new Ext.tree.TreeSorter(tree,{ folderSort : true });
12.树形节点视图 Ext.tree.TreeNodeUI
Ext.treeTreeNodeUI是生成Ext.tree.TreeNode实例时默认使用的视图组件. 在生成每一个Ext.tree.TreeNode实例时,它会先查找this.attributes.uiProvider和this.defaultUI. 如果有任何一个属性存在,它就会使用这个属性创建自己的视图. 如果这两个属性都不存在就会适应Ext.tree.TreeNodeUI创建视图. 因此,在属性结构中通常都使用Ext.tree.TreeNodeUI作为树形节点的视图. 可以通过node.ui的方式获得某个Ext.tree.TreeNode实例对应的Ext.tree.TreeNodeUI
[{ text : '01', children : [ { text : '01-01' , leaf : true , checked : false }, { text : '01-02' , leaf : true , checked : false } ] },{ text :'02', children : [ { text : '02-01' , leaf : true , checked : false }, { text : '02-02' , leaf : true , checked : false } ] }]index.jsp
<style type="text/css"> .big { font-weight: bold; } </style> <script type="text/javascript" defer> Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = '<%=rootpath%>/ext/resources/images/default/s.gif'; var tree = new Ext.tree.TreePanel({ region: 'center', collapsible: true, title: '树形节点视图', width: 200, border : false, autoScroll: true, animate : true, rootVisible: false, split: true, loader : new Ext.tree.TreeLoader({ dataUrl : 'list.txt' }), root : new Ext.tree.AsyncTreeNode({ //设置id,让后台知道应该在何时返回根节点的子点数据 id : '0', text : '我是根' }), listeners: { afterrender: function(node) { //展开树 tree.expandAll(); } } }); new Ext.Viewport({ items: [tree] }); tree.on('click',function(node){ //当用户点击一个节点,会获得节点对应的Ext.tree.TreeNodeUI实例 var treeNodeUI = node.ui; //最后调用addClass()方法把文字转化为粗体 treeNodeUI.addClass('big'); ( function(){ treeNodeUI.removeClass('big'); } ).defer(1000); }); }); </script>
treeNodeUI的方法 getAnchor(),getIconEl(),getTextEl()这3个函数可以分别获取页面上与树形对应的 <a>标签,包含图标的<img>标签,包含文字的<span>标签部分 hide()和show()函数可以控制树形节点是否隐藏 isChecked()和toggleCheck()函数可以判断和修改树形节点中的Checkbox的状态,这两属性必须节点包含Checkbox,否则isChecked()会一直返回false13.表格与树的结合 Ext.ux.tree.ColumnTree()
Ext.ux.tree.ColumnTree属于EXT的扩展件,为了使用Ext.ux.tree.ColumnTree, 我们首先需要引用Ext发布包中的column-tree.css,ColumnNodeUI.css,以及ColumnNodeUI.js三个文件 需要注意的是:我们要给每一个节点设置uiProvider:'col',这样在生成树时TreeLoader会预先定义的uiProviders参数中取得'col'对应的Ext.ux.tree.ColumnNodeUI,用它来作为显示树形节点的视图效果图
<%@ page language="java" pageEncoding="UTF-8"%> <% request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); //获取node参数,对应的是正在展开的节点id String node = request.getParameter("node"); System.out.println("node="+node); String json = "["+ "{km:'深入浅出ExtJs',ks:'12month',js:'',uiProvider:'col',"+ "children:["+ "{km:'ExtJs01',ks:'6month',js:'lwc',uiProvider:'col',leaf:true},"+ "{km:'ExtJs02',ks:'6month',js:'wr',uiProvider:'col',leaf:true}"+ "]}"+ ",{km:'深入浅出Java',ks:'10month',js:'',uiProvider:'col',"+ "children:["+ "{km:'Java01',ks:'4month',js:'tom',uiProvider:'col',leaf:true},"+ "{km:'Java02',ks:'6month',js:'cat',uiProvider:'col',leaf:true}"+ "]}"+ "]"; response.getWriter().write(json); %>
index.jsp
<!-- 使用ColumnTree需要带入这两个文件 --> <link rel="stylesheet" type="text/css" href="<%=rootpath%>/ext/ux/css/ColumnNodeUI.css"/> <script type="text/javascript" src="<%=rootpath%>/ext/ux/ColumnNodeUI.js"></script> <script type="text/javascript" defer> Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = '<%=rootpath%>/ext/resources/images/default/s.gif'; var tree = new Ext.tree.ColumnTree({ //columnTree的宽度要等于columns列总和的宽度,否则会出现错行 width: 451, height: 200, rootVisible:false, autoScroll:false, title: '示例', columns:[{ header:'科目', width:230, dataIndex:'km' },{ header:'课时', width:100, dataIndex:'ks' },{ header:'讲师', width:100, dataIndex:'js' }], loader: new Ext.tree.TreeLoader({ dataUrl:'list.jsp', uiProviders:{ 'col': Ext.tree.ColumnNodeUI } }), root: new Ext.tree.AsyncTreeNode({ //设置id,让后台知道应该在何时返回根节点的子点数据 id : '0', text:'我是根' }), listeners: { afterrender: function(node) { //展开树 tree.expandAll(); } } }); new Ext.Viewport({ items : [tree] }); }); </script>