预览:

demo.html:
<script type="text/javascript" src="js/Ext.ux.MyTreeLoader/MyTreeLoader.js"></script>
<script type="text/javascript" src="treeloader.js"></script>
<div id="tree-ct"></div>treeloader.js:

/**//**
* @include "js/Ext.ux.MyTreeLoader/ColumnNodeUI.js"
* @include "js/Ext.ux.MyTreeLoader/MyTreeLoader.js"
* @include "js/Ext.ux.MyTreeLoader/TreeNodeProvider.js"
*/
Ext.BLANK_IMAGE_URL = 'js/ext-2.0/resources/images/default/s.gif';
var flag = true;// To toggle the refresh


Ext.onReady(function()
{


var treeNodeProvider =
{
data : [],// Property in which are set the data to elaborate
dataUrl : 'addressBook.do?dispatch=queryAddressBook',

getNodes : function()
{ // Here you process your data
return Ext.decode(this.data);
},

setData : function(data)
{// Called internally by
// Ext.tree.MyTreeLoader by the method
// updateTreeNodeProvider
this.data = data;
},
scope : this
// Could be useful to use when you elaborates data to switch the
// context
not used in this example and it's not required
};


var treeNodeProvider2 =
{
data : [],// Property in which are set the data to elaborate
dataUrl : 'companyGroup.do?dispatch=queryGroup',

getNodes : function()
{ // Here you process your data
return Ext.decode(this.data);
},

setData : function(data)
{// Called internally by
// Ext.tree.MyTreeLoader by the method
// updateTreeNodeProvider
this.data = data;
},
scope : this
// Could be useful to use when you elaborates data to switch the
// context
not used in this example and it's not required
};


var myTreeLoader = new Ext.tree.MyTreeLoader(
{
treeNodeProvider : treeNodeProvider
});


var myTreeLoader2 = new Ext.tree.MyTreeLoader(
{
treeNodeProvider : treeNodeProvider2
});

myTreeLoader.updateTreeNodeProvider(myTreeLoader);// if you want to
// "preload"
// the TreePanel with this
// data


var ajaxCallGetDataForTree = function(inputParameters)
{
treePanel.body.mask("Loading data
");
setTimeout(ajaxCallbackGetDataForTree, 1000);
}


var ajaxCallbackGetDataForTree = function()
{

treePanel.body.unmask();

treePanel.body.highlight('#c3daf9',
{
block : true
});
// Simulating that I have received the response that is treeData2 from
// the callback of the ajaxCall
var rootNode = treePanel.getRootNode();// get the rootnode
var loader = treePanel.getLoader();// Get the loader, note that is of
// type MyTreeLoader
loader.updateTreeNodeProvider(myTreeLoader);
loader.load(rootNode);
}


var ajaxCallGetDataForTree2 = function(inputParameters)
{
treePanel.body.mask("Loading data
");
setTimeout(ajaxCallbackGetDataForTree2, 1000);
}


var ajaxCallbackGetDataForTree2 = function()
{

treePanel.body.unmask();

treePanel.body.highlight('#c3daf9',
{
block : true
});
// Simulating that I have received the response that is treeData2 from
// the callback of the ajaxCall
var rootNode = treePanel.getRootNode();// get the rootnode
var loader = treePanel.getLoader();// Get the loader, note that is of
// type MyTreeLoader
loader.updateTreeNodeProvider(myTreeLoader2);
loader.load(rootNode);

}

var flag = true;

var basePanelCfg =
{
title : "AJAX式多数据源及节点异步加载",
preloadChildren : true,
lines : false,
clearOnLoad : true,
rootVisible : false,
containerScroll : true,
frame : false,
collapsible : false,
animate : true,
loader : myTreeLoader,

tbar : [
{
text : "加载通讯录",

handler : function()
{
// Simulating change the treeNodeProvider of the loader
var rootNode = treePanel.getRootNode();// get the rootnode
var loader = treePanel.getLoader();// Get the loader, note that
// is of type MyTreeLoader
loader.setTreeNodeProvider(treeNodeProvider);
// Simulating an ajax call
ajaxCallGetDataForTree();
}

},
{
text : "加载组织",

handler : function()
{
// Simulating change the treeNodeProvider2 of the loader
var rootNode = treePanel.getRootNode();// get the rootnode
var loader = treePanel.getLoader();// Get the loader, note that
// is of type MyTreeLoader
loader.setTreeNodeProvider(treeNodeProvider2);
// Simulating a different ajax call
ajaxCallGetDataForTree2();
}
}]
};

var treePanel = new Ext.tree.TreePanel(basePanelCfg);


var root = new Ext.tree.AsyncTreeNode(
{
text : 'Root',
draggable : false,
id : '1'
});

treePanel.setRootNode(root);
treePanel.render('tree-ct');
});

js/Ext.ux.MyTreeLoader/MyTreeLoader.js:

/**//*
* Version 0.2.3
*
* Ext.tree.MyTreeLoader
*
* @author Dott. Ing. Marco Bellocchi @date 24. April 2008 @license
* Ext.tree.MyTreeLoader.js is licensed under the terms of the Open Source LGPL
* 3.0 license.
*
* @include "js/Ext.ux.MyTreeLoader/ColumnNodeUI.js" @include
* "js/Ext.ux.MyTreeLoader/MyTreeLoader.js" @include
* "js/Ext.ux.MyTreeLoader/TreeNodeProvider.js"
*
* License details: http://www.gnu.org/licenses/lgpl.html
*/


Ext.tree.MyTreeLoader = function(config)
{
// @private
var canFireLoadEvent = true;// private
// @private
var treeNodeProvider = null;
// @private
var loading = false;

Ext.apply(this, config);
Ext.tree.MyTreeLoader.superclass.constructor.call(this, config);
// TO FIX I need to do that for retro compatibility, but you MUST use
// getTreeNodeProvider to have access to it!
treeNodeProvider = this.treeNodeProvider;
// dataUrl = this.dataUrl;

// @private

var processResponse = function(o, node, callback)
{

try
{
node.beginUpdate();

for (var i = 0, len = o.length; i < len; i++)
{
var n = this.createNode(o[i]);

if (n)
{
node.appendChild(n);
}
}
node.endUpdate();

} catch (e)
{
canFireLoadEvent = false;
this.fireEvent("loadexception", this, node, treeNodeProvider.data);
}
// make sure we notify
// the node that we finished

if (typeof callback == "function")
{
callback();
}
if (canFireLoadEvent === true)
this.fireEvent("load", this, node, treeNodeProvider.data);// Passing
}.createDelegate(this);

// @private

var requestData = function(node, callback)
{

if (this.fireEvent("beforeload", this, node, callback) !== false)
{

this.transId = Ext.Ajax.request(
{
method : this.requestMethod,
url : treeNodeProvider.dataUrl || treeNodeProvider.url,
// success: this.handleResponse,
success : handleResponse,
failure : this.fireEvent("loadexception", this, node,
treeNodeProvider.data),
scope : this,

argument :
{
callback : callback,
node : node
},
params : this.getParams(node)
});


} else
{
canFireLoadEvent = false;
}
}.createDelegate(this);

// @private

var handleResponse = function(response)
{
var a = response.argument;
this.processResponse(response, a.node, a.callback);
this.fireEvent("load", this, a.node, response);
}.createDelegate(this);

// @public

this.load = function(node, callback)
{
canFireLoadEvent = true;// Reset the flag

if (this.clearOnLoad)
{

while (node.firstChild)
{
var tmpNode = node.firstChild;
node.removeChild(tmpNode);
tmpNode.destroy();// Destroy actually cascades, see,
// http://extjs.com/forum/showthread.php?t=14993
}
}

if (this.doPreload(node))
{ // preloaded json children

if (typeof callback == "function")
{
callback();
}

} else if (treeNodeProvider)
{
requestData(node, callback);
}
}

// @public

this.isLoading = function()
{
return loading;
}

// @public

this.updateTreeNodeProvider = function(obj)
{

if (treeNodeProvider)
{
treeNodeProvider.setData(obj);
}
}

// @public

this.getTreeNodeProvider = function()
{
return treeNodeProvider;
}
// Set a new treeNodeProvider
// @public

this.setTreeNodeProvider = function(newTreeNodeProvider)
{
if (newTreeNodeProvider == null
|| (typeof newTreeNodeProvider == 'undefined'))
throw 'setTreeNodeProvider, newTreeNodeProvider == null || (typeof newTreeNodeProvider == undefined)';
treeNodeProvider = newTreeNodeProvider;
}

};
Ext.tree.MyTreeLoader = Ext.extend(Ext.tree.MyTreeLoader, Ext.tree.TreeLoader);
