在使用Extjs树控件的时候有个不方便的地方就是不支持简单的平行数据,如:
[
{"text": "North America","id": "NA","parentId": ""},
{"text": "Unites States","id": "USA","parentId": "NA"},
{"text": "Redwood City","id": "RCI","parentId": "USA"},
{"text": "Frederick, MD","id": "FMD","parentId": "USA"}
]
只支持嵌套的数据,如:
[{
"text": "North America",
"id": "NA",
"parentId": "",
"leaf": false,
"children": [{
"text": "Unites States",
"id": "USA",
"parentId": "NA",
"leaf": false,
"children": [
{
"text": "Redwood City",
"id": "RCI",
"parentId": "USA",
"leaf": true
},
{
"text": "Frederick, MD",
"id": "FMD",
"parentId": "USA",
"leaf": true
}]
}]
}]
我的解决方案是继承Ext.data.reader.Json来实现的;
源码如下:
/**
* Created by jiawenjun on 2015/7/29.
* 将列表数据解析成树形数据,以简化树的应用,10万条数据以内解析速度无压力:)
* 配置项:
* treeId ID字段名
* treeParentId 父ID字段名(默认值:id)
* allowCheck:true 允许树支持Checkbox操作的回调函数
* checked(record) 是否选中状态的回调数据
* dataRootProperty: 'result.content' 数据根
* expandDepth:int 树节点展开深度
*/
Ext.define('Ext.ux.data.reader.FastTreeReader', {
extend: 'Ext.data.reader.Json',
alias: 'reader.fasttreereader',
dictData:{},myFieldMapping:null,
/*当proxy的类型为memory时*/
readRecords:function(data, readOptions,internalReadOptions){
var treeJson=data;
if(!!this.sourceData===false){
treeJson=this.parse(data);
}
return this.callParent([treeJson, readOptions, internalReadOptions]);
},
/*当proxy的类型为ajax时*/
getResponseData: function (response) {
try {
this.responseData = Ext.decode(response.responseText);
} catch (ex) {
Ext.Logger.warn('无法解析服务器返回的JSON数据!');
return this.createReadError(ex.message);
}
var treeJson=this.parse(this.responseData);
return treeJson;
},
parse:function(json){
var treeJson=this.myGetTreeJson(json);
return treeJson;
},
myGetTreeJson:function(data){
this.sourceData = data;
if (this.dataRootProperty) {
this.extraData(this.dataRootProperty);
}
var dict={},pid=this.treeParentId || 'parentId',id=this.treeId || 'id';
Ext.Array.each(this.sourceData,function(record){
dict[record[id]]=Ext.clone(record);
},this);
Ext.Array.each(this.sourceData,function(record){
var t=dict[record[pid]];
if(t){
if(t.children){
t.children.push(record);
}else{
t.children=[record];
}
}
},this);
this.dictData=dict;
var rootNodes=[];
Ext.Array.each(this.sourceData,function(record){
if(!dict[record[pid]]){
rootNodes.push(record);
}
});
this.rootNodes=rootNodes;
var treeJson = this.getTreeJson();
return treeJson;
},
getTreeFromData: function (arr) {
this.responseData = arr;
this.sourceData = this.responseData;
if (this.dataRootProperty) {
this.extraData(this.dataRootProperty);
}
var treeJson = this.getTreeJson();
return treeJson;
},
myGetIdName: function () {
return this.treeId || 'id';
},
myGetPidName: function () {
return this.treeParentId || 'parentId'
},
getTreeJson: function () {
var me = this,result=[];
var rootNodes=me.rootNodes;
Ext.Array.each(rootNodes,function(record){
record["nodeDepth"]=1;
if (this.hasChildren(record)) {
record.leaf = false;
record.children = this.myRecursive(record);
}
else {
record.leaf = true;
}
if (this.allowCheck) {
var checked=this.getChecked(record);
if(checked===true||checked===false){
record.checked=checked;
}
}
if (this.expandDepth) {
if (record.nodeDepth <= this.expandDepth) {
record.expanded = true;
}
} else {
record.expanded = false;
}
result.push(record);
},this);
return result;
},
/*
* 递归函数(解析成树形数据)
* */
myRecursive: function (parent) {
var result = [];
var childrens = this.getChildrens(parent);
Ext.Array.each(childrens, function (item) {
var record = item;
record.nodeDepth = parent.nodeDepth + 1;
if (this.hasChildren(item)) {
record.leaf = false;
record.children = this.myRecursive(record);
}
else {
record.leaf = true;
}
if (this.allowCheck) {
var checked=this.getChecked(record);
if(checked===true||checked===false){
record.checked=checked;
}
}
if (this.expandDepth) {
if (record.nodeDepth <= this.expandDepth) {
record.expanded = true;
}
} else {
record.expanded = false;
}
result.push(record);
}, this);
return result;
},
/*
* 获取儿子列表
*/
getChildrens: function (parent) {
var pid=this.treeParentId || 'parentId',id=this.treeId || 'id';
return this.dictData[parent[id]].children;
},
/*
* 是否包含儿子节点
*/
hasChildren: function (parent) {
var pid=this.treeParentId || 'parentId',id=this.treeId || 'id';
return !!(this.dictData[parent[id]].children);
},
/*
*以支持选中状态的回调数据checked
* */
getChecked: function (record) {
if (Ext.isFunction(this.checked)) {
return this.checked(record);
}
return false;
},
/*
* 提取数据
* */
extraData: function (rootProperty, sourceData) {
var rootPro = rootProperty.split('.');
Ext.Array.each(rootPro, function (item) {
if (!Ext.isEmpty(item)) {
this.sourceData = this.sourceData[item]
}
}, this);
}
});
示例一:
//使用内存数据
Ext.define('EquiTree',{
extend:'Ext.tree.Panel',
xtype:'equitree',
requires:['Ext.ux.data.reader.FastTreeReader'],
rootVisible: false,
useArrows:true,
store:{
type:'tree',
fields:[],
proxy:{
type:'memory',
data:[
{"text": "North America","id": "NA","parentId": ""},
{"text": "Unites States","id": "USA","parentId": "NA"},
{"text": "Redwood City","id": "RCI","parentId": "USA"},
{"text": "Frederick, MD","id": "FMD","parentId": "USA"}
],
reader:{
type:'fasttreereader'
}
}
}
});
//动态加载数据方式:
store.setProxy({type:'memory',
data:data,
reader:{
type:'fasttreereader',
expandDepth:2
}});
store.load();
示例二:
//使用Ajax请求
Ext.define('EquiTree',{
extend:'Ext.tree.Panel',
xtype:'equitree',
requires:['Ext.ux.data.reader.FastTreeReader'],
rootVisible: false,
useArrows:true,
store:{
type:'tree',
fields:[],
proxy:{
type:'ajax',
url:'您的请求地址',
reader:{
type:'fasttreereader',
//其他配置项请参照源码说明及其父类Ext.data.reader.Json
}
}
}
});
备注:以上代码在Extjs5.1上测试通过,大家也可以把这个使用FastTreeReader自己封装一个treestore,以提高开发效率;