近期在项目中遇到了一个需求:需要实现一个带树形结构的 ComboBox 下拉框,即 Extjs 树形下拉框。先来看一下最终效果——这种功能在 Extjs 原生组件中并不存在,必须自行开发。通过网络调研,参考了多位开发者的实现思路,结合自己的理解进行整合,最终封装成了 Ext.ux.TreeCombo 自定义组件。以下是完整代码,可直接复制使用。
复制代码 代码如下:
Ext.ux.TreeCombo = Ext.extend(Ext.form.ComboBox, { constructor: function (cfg) { cfg = cfg || {}; Ext.ux.TreeCombo.superclass.constructor.call(this, Ext.apply({ maxHeight: 300, editable: false, mode: 'local', triggerAction: 'all', rootVisible: false, selectMode: 'all' }, cfg)); }, store: new Ext.data.SimpleStore({ fields: [], data: [[]] }), // 重写onViewClick,使展开树结点是不关闭下拉框 onViewClick: function (doFocus) { var index = this.view.getSelectedIndexes()[0], s = this.store, r = s.getAt(index); if (r) { this.onSelect(r, index); } if (doFocus !== false) { this.el.focus(); } }, tree: null, // 隐藏值 hiddenValue: null, getHiddenValue: function () { return this.hiddenValue; }, getValue: function () { //增加适用性,与原来combo组件一样 return this.hiddenValue; }, setHiddenValue: function (code, dispText) { this.setValue(code); Ext.form.ComboBox.superclass.setValue.call(this, dispText); this.hiddenValue = code; }, initComponent: function () { var _this = this; var tplRandomId = 'deptcombo_' + Math.floor(Math.random() * 1000) + this.tplId this.tpl = "
" this.tree = new Ext.tree.TreePanel({ border: false, enableDD: false, enableDrag: false, rootVisible: _this.rootVisible || false, autoScroll: true, trackMouseOver: true, height: _this.maxHeight, lines: true, singleExpand: true, root: new Ext.tree.AsyncTreeNode({ id: _this.rootId, text: _this.rootText, iconCls: 'ico-root', expanded: true, leaf: false, border: false, draggable: false, singleClickExpand: false, hide: true }), loader: new Ext.tree.TreeLoader({ nodeParameter: 'ID', requestMethod: 'GET', dataUrl: _this.url }) }); this.tree.on('click', function (node) { if ((_this.selectMode == 'leaf' && node.leaf == true) || _this.selectMode == 'all') { if (_this.fireEvent('beforeselect', _this, node)) { _this.fireEvent('select', _this, node); } } }); this.on('select', function (obj, node) { var dispText = node.text; var code = node.id; obj.setHiddenValue(code, dispText); obj.collapse(); }); this.on('expand', function () { this.tree.render(tplRandomId); }); Ext.ux.TreeCombo.superclass.initComponent.call(this); } }) Ext.reg("treecombo", Ext.ux.TreeCombo);组件开发完成后,需要在主页面中引入必要的 Extjs 类库文件。请注意引入顺序与文件路径的准确性:
复制代码 代码如下:
其中 login.js 文件包含了业务逻辑代码,以下为核心代码片段(完整实现请根据实际项目需求进行调整):
复制代码 代码如下:
/* File Created: 五月 27, 2013 */ Ext.onReady(function () { var _window = new Ext.Window({ title: "查询条件", renderTo: Ext.getBody(), frame: true, plain: true, buttonAlign: "center", closeAction: "hide", maximizable: true, closable: true, bodyStyle: "padding:20px", width: 350, height: 300, layout: "form", lableWidth: 110, defaults: { xtype: "textfield", width: 180 }, // ... 此处省略窗口内的具体组件配置,实际使用时根据需求补充 }); });
至此,文章开头展示的树形下拉框效果便成功实现。该组件的核心实现思路如下:基于 Ext.form.ComboBox 进行扩展,在组件展开时动态渲染一个 TreePanel 到下拉框的模板区域中;通过重写 onViewClick 方法,防止展开树节点时意外关闭下拉框;同时监听树节点的点击事件,用于设置隐藏值和显示文本。

