treeview代码参见前一篇
在treeview修改本地化实现后,就要考虑如何去实现自动加载树的代码
在ExtJS里是通过继承并扩展TreePanel功能实现的,但是YUI3的widget继承有些问题(见Datatable)
还是和Datatable的处理方式一样,为Treeview编写一个专门的plugin插件来解决问题
这个plugin做两件事:
1、在树创建后创建树的根节点及第一层节点,并定义各节点是否可展开
2、在用户操作展开节点时获取下一层节点
这样,在前台脚本里,创建树的代码就简洁到了极致
首先,module里需要引入本地的treeview模块及插件模块(自己编写的dataquery),然后指定名称创建树
var Y = YUI({ modules: { 。。。。。。 treeview: { async: false, fullpath: '../scripts/gallery/treeview.js' }, dataquery: { async: false, fullpath: '../scripts/core/dataquery.js' } } }).use(。。。。。。。 'dataquery', 'treeview', function(Y) { var treeview = new Y.TreeView({ startCollapsed: false, toggleOnLabelClick: false }); treeview.plug(Y.TreePlugin.TreeLoaderPlugin, { treename: 'navigator' }); treeview.render("#cattree1"); });
这里可以看到,跟标准的demo代码比,完全没有了啰嗦的treenode的数据,treeview创建的代码只需要1个参数:startCollapsed,设定开始时根展开(toggleOnlabelClick可有可无),然后再plug一下TreeLoaderPlugin就可以了
效果图如下,比原始的那个没图的版本已经耐看多了,+-号标记还需要再改小点,感觉大了有点难看TreeLoaderPlugin的代码如下:
function TreeLoaderPlugin(config) { TreeLoaderPlugin.superclass.constructor.apply(this, arguments); }; Y.mix(TreeLoaderPlugin, { NAME: 'treeLoaderPlugin', NS: 'treeloaderplugin', ATTRS: { treename: { value: '' } } }); Y.extend(TreeLoaderPlugin, Y.Plugin.Base, { initializer: function() { var tree = this.get(HOST); this.onHostEvent('nodeClick', this._treenodeclick); this.onHostEvent('nodeExpand', this._treenodeexpand); var plugin = this; var configuration = { method: 'POST', sync: true, data: { name: this.get('treename') }, on: { complete: function(o) { var result = Y.JSON.parse(o.data.responseText); var treenode = new Y.TreeNode({ label: unescape(result.label), icon: result.iconCls, collapsed: true, nodeId: '-1', expandable: true }); treenode.handler = unescape(result.handler); treenode.dataRefresh = result.expandRefresh == true; treenode.dataRead = false; treenode.dataID = ""; tree.add(treenode); plugin._loadsub(treenode); } } }; var rio = new Y.IO({ emitFacade: true, bubbles: true }); rio.send('../Tree/Get', configuration); }, _treenodeclick: function(e) { if (e.treenode.handler != '') { eval(e.treenode.handler); } }, _treenodeexpand: function(e) { this._loadsub(e.treenode); }, _loadsub: function(node) { if (node.dataRefresh == true || node.dataRead == false) { if (node.dataRead && node.size() > 0) { while (node.size() > 0) { node.item(0).remove(); } } node.dataRead = true; var configuration = { method: 'POST', sync: true, data: { name: this.get('treename'), id: node.get('nodeId'), dataID: node.dataID }, on: { complete: function(o) { var list = eval(o.data.responseText); for (var n = 0; n < list.length; n++) { k = list[n]; var treenode = new Y.TreeNode({ label: unescape(k.label), icon: k.iconCls, collapsed: k.autoExpand == true, nodeId: k.id, expandable: k.hasChild }); treenode.handler = unescape(k.handler); treenode.nodeID = k.id; treenode.dataRead = false; if (k.dataID != null) { treenode.dataID = k.dataID; } else { treenode.dataID = ""; } treenode.dataRefresh = k.expandRefresh == true; node.add(treenode); } } } }; var rio = new Y.IO({ emitFacade: true, bubbles: true }); rio.send('../Tree/GetChild', configuration); } } }); Y.namespace('TreePlugin'); Y.TreePlugin.TreeLoaderPlugin = TreeLoaderPlugin;
这个plugin通过后台获取树的配置信息并生成树,关于树的后台是如何实现的,这里就不解释了,可以参考ExtFrame相关的架构说明页面
plugin通过Host的nodeClick方法,执行节点上定义的操作,通过Host的nodeExpand方法,拦截节点展开事件,判断节点如果已获取数据,且为非刷新节点,则不响应,如未获取数据,或为每次展开重新刷新节点,则删除子节点并重新加载