TreeGrid.js原路径:http://www.extjs.com/forum/showthread.php?t=37831
效果图(查看附件treegrid.gif)
Ext的treePanel提供了很丰富实用功能,可以现自由拖拽、添加、删除等,但是缺点是只能显示一行信息,无法满足需求;Ext2.0的Demo里有提供一个Cloumn tree的实现,但是无法使用checkbox事件,为了让tree+cloumn+checkbox和平共处,本来打算改一下Cloumn tree的实现的,写之前浏览了一下ext论坛的扩展实现和插件,发现有写好的,就直接奉行拿来主义了。作者有讲说这是一个初期版本,需要改进的地方挺多,不管先拿过来看看再说,demo包在上面的路径可以下载到。
1、jsp页面需要引用的文件:
<script type='text/javascript' src='../../../ExtJS/adapter/ext/ext-base.js'></script> <script type='text/javascript' src='../../../ExtJS/ext-all-debug.js'></script> <script type='text/javascript' src='../../../ExtJS/examples/grid/RowExpander.js'></script> <script type='text/javascript' src='../../TreeGrid.js'></script> <link rel="stylesheet" type="text/css" href="../../../ExtJS/resources/css/ext-all.css" /> <link rel="stylesheet" type="text/css" href="../../css/TreeGrid.css" /> <link rel="stylesheet" type="text/css" href="../../css/TreeGridLevels.css" />
以上文件ExtJS目录下都是ext2.0包里自带,TreeGrid.js可以在附件里下载到;样式文件TreeGrid.clss必须要,TreeGridLevels.css可以不须要引用,如果你认为这个样式好看的话也可以引入。
2、来看一下demo里的实现代码:
Controller = function() { function createGrid() { var data = [ {"company":"0. Johnson & Johnson","price":64.72,"change":0.06,"pct_change":0.09,"last_change":"9\/1 12:00am","_id":1,"_parent":null,"_level":1,"_lft":1,"_rgt":98,"_is_leaf":false}, {"company":"1. American International Group, Inc.","price":64.13,"change":0.31,"pct_change":0.49,"last_change":"9\/1 12:00am","_id":2,"_parent":1,"_level":2,"_lft":2,"_rgt":17,"_is_leaf":false}, {"company":"2. Alcoa Inc","price":29.01,"change":0.42,"pct_change":1.47,"last_change":"9\/1 12:00am","_id":3,"_parent":1,"_level":2,"_lft":18,"_rgt":65,"_is_leaf":false}, {"company":"3. The Coca-Cola Company","price":45.07,"change":0.26,"pct_change":0.58,"last_change":"9\/1 12:00am","_id":4,"_parent":1,"_level":2,"_lft":66,"_rgt":79,"_is_leaf":false}, {"company":"4. Citigroup, Inc.","price":49.37,"change":0.02,"pct_change":0.04,"last_change":"9\/1 12:00am","_id":5,"_parent":null,"_level":1,"_lft":99,"_rgt":100,"_is_leaf":true}, {"company":"5. Hewlett-Packard Co.","price":36.53,"change":-0.03,"pct_change":-0.08,"last_change":"9\/1 12:00am","_id":6,"_parent":null,"_level":1,"_lft":101,"_rgt":118,"_is_leaf":false}, {"company":"6. McDonald's Corporation","price":36.76,"change":0.86,"pct_change":2.4,"last_change":"9\/1 12:00am","_id":7,"_parent":1,"_level":2,"_lft":80,"_rgt":85,"_is_leaf":false}, {"company":"7. The Procter & Gamble Company","price":61.91,"change":0.01,"pct_change":0.02,"last_change":"9\/1 12:00am","_id":8,"_parent":4,"_level":3,"_lft":67,"_rgt":76,"_is_leaf":false}, {"company":"8. Johnson & Johnson","price":64.72,"change":0.06,"pct_change":0.09,"last_change":"9\/1 12:00am","_id":9,"_parent":2,"_level":3,"_lft":3,"_rgt":6,"_is_leaf":false}, {"company":"9. Microsoft Corporation","price":25.84,"change":0.14,"pct_change":0.54,"last_change":"9\/1 12:00am","_id":10,"_parent":7,"_level":3,"_lft":81,"_rgt":82,"_is_leaf":true}, {"company":"10. E.I. du Pont de Nemours and Company","price":40.48,"change":0.51,"pct_change":1.28,"last_change":"9\/1 12:00am","_id":11,"_parent":3,"_level":3,"_lft":19,"_rgt":36,"_is_leaf":false}, {"company":"11. Honeywell Intl Inc","price":38.77,"change":0.05,"pct_change":0.13,"last_change":"9\/1 12:00am","_id":12,"_parent":11,"_level":4,"_lft":20,"_rgt":29,"_is_leaf":false}, {"company":"12. Microsoft Corporation","price":25.84,"change":0.14,"pct_change":0.54,"last_change":"9\/1 12:00am","_id":13,"_parent":4,"_level":3,"_lft":77,"_rgt":78,"_is_leaf":true}, {"company":"13. American International Group, Inc.","price":64.13,"change":0.31,"pct_change":0.49,"last_change":"9\/1 12:00am","_id":14,"_parent":null,"_level":1,"_lft":119,"_rgt":122,"_is_leaf":false}, {"company":"14. Hewlett-Packard Co.","price":36.53,"change":-0.03,"pct_change":-0.08,"last_change":"9\/1 12:00am","_id":15,"_parent":null,"_level":1,"_lft":123,"_rgt":136,"_is_leaf":false} ]; // add in some dummy descriptions and loaded flag for (var i = 0; i < data.length; i++) { data[i].desc = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed metus nibh, sodales a, porta at, vulputate eget, dui. Pellentesque ut nisl. Maecenas tortor turpis, interdum non, sodales non, iaculis ac, lacus. Vestibulum auctor, tortor quis iaculis malesuada, libero lectus bibendum purus, sit amet tincidunt quam turpis vel lacus. In pellentesque nisl non sem. Suspendisse nunc sem, pretium eget, cursus a, fringilla vel, urna.<br/><br/>Aliquam commodo ullamcorper erat. Nullam vel justo in neque porttitor laoreet. Aenean lacus dui, consequat eu, adipiscing eget, nonummy non, nisi. Morbi nunc est, dignissim non, ornare sed, luctus eu, massa. Vivamus eget quam. Vivamus tincidunt diam nec urna. Curabitur velit.'; data[i]._is_loaded = true; } var expander = new Ext.grid.RowExpander({ tpl : new Ext.Template( '<p><b>Company:</b> {company}</p><br>', '<p><b>Summary:</b> {desc}</p>' ) }); // create the data store var record = Ext.data.Record.create([ {name: 'company'}, {name: 'price', type: 'float'}, {name: 'change', type: 'float'}, {name: 'pct_change', type: 'float'}, {name: 'last_change', type: 'date', dateFormat: 'n/j h:ia'}, {name: 'desc'}, {name: '_id', type: 'int'}, {name: '_level', type: 'int'}, {name: '_lft', type: 'int'}, {name: '_rgt', type: 'int'}, {name: '_is_leaf', type: 'bool'} ]); var store = new Ext.ux.maximgb.treegrid.NestedSetStore({ autoLoad : true, reader: new Ext.data.JsonReader({id: '_id'}, record), proxy: new Ext.data.MemoryProxy(data) }); // create the Grid var grid = new Ext.ux.maximgb.treegrid.GridPanel({ store: store, master_column_id : 'company', columns: [ expander, {id:'company',header: "Company", width: 160, sortable: true, dataIndex: 'company'}, {header: "Price", width: 75, sortable: true, renderer: 'usMoney', dataIndex: 'price'}, {header: "test", width: 75, sortable: true, renderer: 'usMoney', dataIndex: 'price',renderer:showbox,align:'center'}, {header: "Change", width: 75, sortable: true, renderer: change, dataIndex: 'change'}, {header: "% Change", width: 75, sortable: true, renderer: pctChange, dataIndex: 'pct_change'}, {header: "Last Updated", width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'last_change'} ], stripeRows: true, autoExpandColumn: 'company', title: 'Array Grid', root_title: 'Companies', plugins: expander, viewConfig : { enableRowBody : true } }); var vp = new Ext.Viewport({ layout : 'fit', items : grid }); grid.getSelectionModel().selectFirstRow(); } function showbox(value){ return "<input type=checkbox name='item' value='"+value+"'>"; } // example of custom renderer function function change(val) { if (val > 0) { val = '<span style="color:green;">' + val + '</span>'; } else if(val < 0) { val = '<span style="color:red;">' + val + '</span>'; } return val; } // example of custom renderer function function pctChange(val) { if (val > 0) { val = '<span style="color:green;">' + val + '%</span>'; } else if(val < 0) { val = '<span style="color:red;">' + val + '%</span>'; } return val; } return { init : function() { createGrid(); } } }(); Ext.onReady(Controller.init);
3、数据分析
{"company":"0. Johnson & Johnson","price":64.72,"change":0.06,"pct_change":0.09,"last_change":"9\/1 12:00am","_id":1,"_parent":null,"_level":1,"_lft":1,"_rgt":98,"_is_leaf":false},
这是数组data的其中一行数据,我们可以看到除了业务数据以外,还有几个比较特殊的数据:_id,_parent,_level,_lft,_rgt,_is_leaf。这几个值必须要有的,下面我们来看看这几个属性的作用。
_id:这个不用讲了吧。
_parent:值必须为父级菜单的id值。
_level:菜单级别。
_lft & _rgt:这两个值我看了半天才明白,按照二叉树的索引位置来计算的,具体的请参考http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
_is_leaf: 是不是最终节目节。
注:如果要跑通例子的话,把上面的这几个属性名称前面的'_'下划线都去了吧,不太习惯这样写,所以下面附件里的代码稍微做了一下改动;还有就是如果讨厌计算_lft和_rht的值,可以在数据库里或者在生json的时候就自定义排下序,如果你是按照二叉树的索引位置来排序的话,可以不用设置_lft和_rgt的值,否则会造成子菜单的位置与父菜单不对应的情况。上面是请求的本地的一个数组,下面我把远程请求json的加载方法发一下:
var store = new Ext.ux.maximgb.treegrid.AdjacencyListStore({ autoLoad : true, url: '../tree!list.action?id='+id+'&format=json', reader: new Ext.data.JsonReader( { id: 'id', root: 'menu', totalProperty: 'total', successProperty: 'success' }, record ) });
4、创建Ext.ux.maximgb.treegrid.GridPanel参数说明
master_column_id:值为ColumnModel中设置的需要作为tree显示的一列的id,如上例中的cloumns的第一列"id:'company'",注意要将dataIndex这一列的数据放在第一列显示;
autoExpandColumn: 同上;
root_title:显示的tree的根,值是一个字符串,如果为空会自动获取title的值,都为空里显示root。
其它属性与普通grid用法一样。
之所以选择使用这个而不是cloumn tree是因为在renderer checkbox并触发checkbox事件的时候不会发生错误。如果你想调试运行可以直接去下demo域者跑通这个都可以。不使用远程数据就直接可以在apache环境运行。这里获取远程数据是结合java使用的,也可以改成php的。
下次再发一下TreeGrid源码解读。以上实现方式如果有不正确的地方多指证!