本节为ExtJS表格学习的最后一节,学完我将学习表单与输入控件的内容。
树形表格(TreeGrid)同时具备树形的分级结构和表格的丰富内容。

81538f906060e677441b07542f507284.jpg
先引入扩展组件,老规矩:

//引入扩展组件 
Ext.Loader.setConfig({enabled: true}); 
                     
Ext.Loader.setPath('Ext.ux', '../ExtJS4.2/ux/'); 
                     
Ext.require([ 
             'Ext.data.*', 
             'Ext.grid.*', 
             'Ext.tree.*', 
             'Ext.ux.CheckColumn' 
         ]);

接下来创建TreeGrid

Ext.onReady(function(){ 
    Ext.QuickTips.init(); 
                
    //we want to setup a model and store instead of using dataUrl 
    Ext.define('Task', { 
        extend: 'Ext.data.Model', 
        fields: [ 
            {name: 'task',     type: 'string'}, 
            {name: 'user',     type: 'string'}, 
            {name: 'duration', type: 'string'} 
        ] 
    }); 
    var store = Ext.create('Ext.data.TreeStore', { 
        model: 'Task', 
        proxy: { 
            type: 'ajax', 
            //the store will get the content from the .json file 
            url: 'treegrid-data.json' 
        }, 
        folderSort: true 
    }); 
                    
  //Ext.ux.tree.TreeGrid在UX扩展中也有,但不常用,您可以简单地使用一个tree.TreePanel 
    var tree = Ext.create('Ext.tree.Panel', { 
        title: 'Core Team Projects', 
        width: 500, 
        height: 300, 
        renderTo: 'treegrid', 
        collapsible: true, 
        useArrows: true, 
        rootVisible: false, 
        store: store, 
        multiSelect: true, 
        singleExpand: true, 
                        
      //the 'columns' property is now 'headers' 
        columns: [{ 
            xtype: 'treecolumn', //this is so we know which column will show the tree 
            text: 'Task', 
            flex: 2, 
            sortable: true, 
            dataIndex: 'task' 
        },{ 
            //we must use the templateheader component so we can use a custom tpl 
            xtype: 'templatecolumn', 
            text: 'Duration', 
            flex: 1, 
            sortable: true, 
            dataIndex: 'duration', 
            align: 'center', 
            //add in the custom tpl for the rows 
            tpl: Ext.create('Ext.XTemplate', '{duration:this.formatHours}', { 
                formatHours: function(v) { 
                    if (v < 1) { 
                        return Math.round(v * 60) + ' mins'; 
                    } else if (Math.floor(v) !== v) { 
                        var min = v - Math.floor(v); 
                        return Math.floor(v) + 'h ' + Math.round(min * 60) + 'm'; 
                    } else { 
                        return v + ' hour' + (v === 1 ? '' : 's'); 
                    } 
                } 
            }) 
        },{ 
            text: 'Assigned To', 
            flex: 1, 
            dataIndex: 'user', 
            sortable: true 
        }, { 
            xtype: 'checkcolumn', 
            header: 'Done', 
            dataIndex: 'done', 
            width: 40, 
            stopSelection: false 
        }, { 
            text: 'Edit', 
            width: 40, 
            menuDisabled: true, 
            xtype: 'actioncolumn', 
            tooltip: 'Edit task', 
            align: 'center', 
            icon: '../MyDemo/p_w_picpaths/edit.png', 
            handler: function(grid, rowIndex, colIndex, actionItem, event, record, row) { 
                Ext.Msg.alert('Editing' + (record.get('done') ? ' completed task' : '') , record.get('task')); 
            } 
        }] 
    }); 
});

在列定义中有xtype: 'treecolumn',这是告诉列要以树形列来显示,在以后的表单或其他容器中也会以这样的方式来显示,有panelcolumn等,这里等以后讲到再说。
再看下JSON数据格式,后台只要符合这种形式,EXTJS就会给你自动解析出来:

{"text":".","children": [ 
    { 
        task:'Project: Shopping', 
        duration:13.25, 
        user:'Tommy Maintz', 
        iconCls:'task-folder', 
        expanded: true, 
        children:[{ 
            task:'Housewares', 
            duration:1.25, 
            user:'Tommy Maintz', 
            iconCls:'task-folder', 
            children:[{ 
                task:'Kitchen supplies', 
                duration:0.25, 
                user:'Tommy Maintz', 
                leaf:true, 
                iconCls:'task' 
            },{ 
                task:'Groceries', 
                duration:.4, 
                user:'Tommy Maintz', 
                leaf:true, 
                iconCls:'task', 
                done: true 
            },{ 
                task:'Cleaning supplies', 
                duration:.4, 
                user:'Tommy Maintz', 
                leaf:true, 
                iconCls:'task' 
            },{ 
                task: 'Office supplies', 
                duration: .2, 
                user: 'Tommy Maintz', 
                leaf: true, 
                iconCls: 'task' 
            }] 
        }, { 
            task:'Remodeling', 
            duration:12, 
            user:'Tommy Maintz', 
            iconCls:'task-folder', 
            expanded: true, 
            children:[{ 
                task:'Retile kitchen', 
                duration:6.5, 
                user:'Tommy Maintz', 
                leaf:true, 
                iconCls:'task' 
            },{ 
                task:'Paint bedroom', 
                duration: 2.75, 
                user:'Tommy Maintz', 
                iconCls:'task-folder', 
                children: [{ 
                    task: 'Ceiling', 
                    duration: 1.25, 
                    user: 'Tommy Maintz', 
                    iconCls: 'task', 
                    leaf: true 
                }, { 
                    task: 'Walls', 
                    duration: 1.5, 
                    user: 'Tommy Maintz', 
                    iconCls: 'task', 
                    leaf: true 
                }] 
            },{ 
                task:'Decorate living room', 
                duration:2.75, 
                user:'Tommy Maintz', 
                leaf:true, 
                iconCls:'task', 
                done: true 
            },{ 
                task: 'Fix lights', 
                duration: .75, 
                user: 'Tommy Maintz', 
                leaf: true, 
                iconCls: 'task', 
                done: true 
            }, { 
                task: 'Reattach screen door', 
                duration: 2, 
                user: 'Tommy Maintz', 
                leaf: true, 
                iconCls: 'task' 
            }] 
        }] 
    },{ 
        task:'Project: Testing', 
        duration:2, 
        user:'Core Team', 
        iconCls:'task-folder', 
        children:[{ 
            task: 'Mac OSX', 
            duration: 0.75, 
            user: 'Tommy Maintz', 
            iconCls: 'task-folder', 
            children: [{ 
                task: 'FireFox', 
                duration: 0.25, 
                user: 'Tommy Maintz', 
                iconCls: 'task', 
                leaf: true 
            }, { 
                task: 'Safari', 
                duration: 0.25, 
                user: 'Tommy Maintz', 
                iconCls: 'task', 
                leaf: true 
            }, { 
                task: 'Chrome', 
                duration: 0.25, 
                user: 'Tommy Maintz', 
                iconCls: 'task', 
                leaf: true 
            }] 
        },{ 
            task: 'Windows', 
            duration: 3.75, 
            user: 'Darrell Meyer', 
            iconCls: 'task-folder', 
            children: [{ 
                task: 'FireFox', 
                duration: 0.25, 
                user: 'Darrell Meyer', 
                iconCls: 'task', 
                leaf: true 
            }, { 
                task: 'Safari', 
                duration: 0.25, 
                user: 'Darrell Meyer', 
                iconCls: 'task', 
                leaf: true 
            }, { 
                task: 'Chrome', 
                duration: 0.25, 
                user: 'Darrell Meyer', 
                iconCls: 'task', 
                leaf: true 
            },{ 
                task: 'Internet Exploder', 
                duration: 3, 
                user: 'Darrell Meyer', 
                iconCls: 'task', 
                leaf: true 
            }] 
        },{ 
            task: 'Linux', 
            duration: 0.5, 
            user: 'Aaron Conran', 
            iconCls: 'task-folder', 
            children: [{ 
                task: 'FireFox', 
                duration: 0.25, 
                user: 'Aaron Conran', 
                iconCls: 'task', 
                leaf: true 
            }, { 
                task: 'Chrome', 
                duration: 0.25, 
                user: 'Aaron Conran', 
                iconCls: 'task', 
                leaf: true 
            }] 
        }] 
    } 
]}

这里还有一个扩展功能,如下:
639f8db93387a7c80ea039fed4de0faf.jpg
表头点击箭头就会出现过滤组件,便于筛选数据,每列都有,是不是很丰富啊。
下面看代码:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 
<!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>Hello Extjs4.2</title> 
<link href="../ExtJS4.2/resources/css/ext-all.css" rel="stylesheet"> 
<script src="../ExtJS4.2/ext-all.js"></script> 
<script src="../ExtJS4.2/locale/ext-lang-zh_CN.js"></script> 
<script type="text/javascript"> 
//引入扩展组件 
Ext.Loader.setConfig({enabled: true}); 
      
Ext.Loader.setPath('Ext.ux', '../ExtJS4.2/ux/'); 
      
Ext.require([ 
             'Ext.grid.*', 
             'Ext.data.*', 
             'Ext.ux.grid.FiltersFeature', 
             'Ext.toolbar.Paging', 
             'Ext.ux.ajax.JsonSimlet', 
             'Ext.ux.ajax.SimManager' 
         ]); 
Ext.define('Product', { 
    extend: 'Ext.data.Model', 
    fields: [{ 
        name: 'id', 
        type: 'int' 
    }, { 
        name: 'company' 
    }, { 
        name: 'price', 
        type: 'float' 
    }, { 
        name: 'date', 
        type: 'date', 
        dateFormat: 'Y-m-d' 
    }, { 
        name: 'visible', 
        type: 'boolean' 
    }, { 
        name: 'size' 
    }] 
}); 
Ext.onReady(function(){ 
      
    Ext.ux.ajax.SimManager.init({ 
        delay: 300, 
        defaultSimlet: null 
    }).register({ 
        'myData': { 
            data: [ 
                ['small', 'small'], 
                ['medium', 'medium'], 
                ['large', 'large'], 
                ['extra large', 'extra large'] 
            ], 
            stype: 'json' 
        } 
    }); 
      
    var optionsStore = Ext.create('Ext.data.Store', { 
        fields: ['id', 'text'], 
        proxy: { 
            type: 'ajax', 
            url: 'myData', 
            reader: 'array' 
        } 
    }); 
      
    Ext.QuickTips.init(); 
      
    // for this demo configure local and remote urls for demo purposes 
    var url = { 
        local:  'grid-filter.json',  // static data file 
        remote: 'grid-filter.php' 
    }; 
      
    // configure whether filter query is encoded or not (initially) 
    var encode = false; 
      
    // configure whether filtering is performed locally or remotely (initially) 
    var local = true; 
      
    var store = Ext.create('Ext.data.JsonStore', { 
        // store configs 
        autoDestroy: true, 
        model: 'Product', 
        proxy: { 
            type: 'ajax', 
            url: (local ? url.local : url.remote), 
            reader: { 
                type: 'json', 
                root: 'data', 
                idProperty: 'id', 
                totalProperty: 'total' 
            } 
        }, 
        remoteSort: false, 
        sorters: [{ 
            property: 'company', 
            direction: 'ASC' 
        }], 
        pageSize: 50 
    }); 
      
    var filters = { 
        ftype: 'filters', 
        // encode and local configuration options defined previously for easier reuse 
        encode: encode, // json encode the filter query 
        local: local,   // defaults to false (remote filtering) 
      
        // Filters are most naturally placed in the column definition, but can also be 
        // added here. 
        filters: [{ 
            type: 'boolean', 
            dataIndex: 'visible' 
        }] 
    }; 
      
    // use a factory method to reduce code while demonstrating 
    // that the GridFilter plugin may be configured with or without 
    // the filter types (the filters may be specified on the column model 
    var createColumns = function (finish, start) { 
      
        var columns = [{ 
            dataIndex: 'id', 
            text: 'Id', 
            // instead of specifying filter config just specify filterable=true 
            // to use store's field's type property (if type property not 
            // explicitly specified in store config it will be 'auto' which 
            // GridFilters will assume to be 'StringFilter' 
            filterable: true, 
            width: 30 
            //,filter: {type: 'numeric'} 
        }, { 
            dataIndex: 'company', 
            text: 'Company', 
            id: 'company', 
            flex: 1, 
            filter: { 
                type: 'string' 
                // specify disabled to disable the filter menu 
                //, disabled: true 
            } 
        }, { 
            dataIndex: 'price', 
            text: 'Price', 
            filter: { 
                //type: 'numeric'  // specify type here or in store fields config 
            }, 
            width: 70 
        }, { 
            dataIndex: 'size', 
            text: 'Size', 
            filter: { 
                type: 'list', 
                store: optionsStore 
                //,phpMode: true 
            } 
        }, { 
            dataIndex: 'date', 
            text: 'Date', 
            filter: true, 
            renderer: Ext.util.Format.dateRenderer('m/d/Y') 
        }, { 
            dataIndex: 'visible', 
            text: 'Visible' 
            // this column's filter is defined in the filters feature config 
        }]; 
      
        return columns.slice(start || 0, finish); 
    }; 
      
    var grid = Ext.create('Ext.grid.Panel', { 
        border: false, 
        store: store, 
        columns: createColumns(4), 
        loadMask: true, 
        features: [filters], 
        dockedItems: [Ext.create('Ext.toolbar.Paging', { 
            dock: 'bottom', 
            store: store 
        })], 
        emptyText: 'No Matching Records' 
    }); 
      
    // add some buttons to bottom toolbar just for demonstration purposes 
    grid.child('pagingtoolbar').add([ 
        '->', 
        { 
            text: 'Encode: ' + (encode ? 'On' : 'Off'), 
            tooltip: 'Toggle Filter encoding on/off', 
            enableToggle: true, 
            handler: function (button, state) { 
                var encode = (grid.filters.encode !== true); 
                var text = 'Encode: ' + (encode ? 'On' : 'Off'); 
                grid.filters.encode = encode; 
                grid.filters.reload(); 
                button.setText(text); 
            } 
        }, 
        { 
            text: 'Local Filtering: ' + (local ? 'On' : 'Off'), 
            tooltip: 'Toggle Filtering between remote/local', 
            enableToggle: true, 
            handler: function (button, state) { 
                var local = (grid.filters.local !== true), 
                    text = 'Local Filtering: ' + (local ? 'On' : 'Off'), 
                    newUrl = local ? url.local : url.remote, 
                    store = grid.view.getStore(); 
      
                // update the GridFilter setting 
                grid.filters.local = local; 
                // bind the store again so GridFilters is listening to appropriate store event 
                grid.filters.bindStore(store); 
                // update the url for the proxy 
                store.proxy.url = newUrl; 
      
                button.setText(text); 
                store.load(); 
            } 
        }, 
        { 
            text: 'All Filter Data', 
            tooltip: 'Get Filter Data for Grid', 
            handler: function () { 
                var data = Ext.encode(grid.filters.getFilterData()); 
                Ext.Msg.alert('All Filter Data',data); 
            } 
        },{ 
            text: 'Clear Filter Data', 
            handler: function () { 
                grid.filters.clearFilters(); 
            } 
        },{ 
            text: 'Add Columns', 
            handler: function () { 
                if (grid.headerCt.items.length < 6) { 
                    grid.headerCt.add(createColumns(6, 4)); 
                    grid.view.refresh(); 
                    this.disable(); 
                } 
            } 
        } 
    ]); 
      
    var win = Ext.create('Ext.Window', { 
        title: 'Grid Filters Example', 
        height: 400, 
        width: 700, 
        layout: 'fit', 
        items: grid 
    }).show(); 
      
    store.load(); 
}); 
</script> 
</head> 
<body> 
<h1>我的ExtJS4.2学习之路</h1> 
<hr /> 
作者:束洋洋 
开始日期:2013年11月26日 22:57:53 
<h2>深入浅出ExtJS之树形表格</h2> 
<div id="grid"></div> 
</body> 
</html>

连载中,请大家继续关注!本文出自我的个人网站思考者日记网