先来一个效果图,已在Firefox3.5、IE7、Chrome3中测试正常
完整应用和代码请转到 http://www.iteye.com/topic/553020
拜读了[Ext 3.x + Ext 2.x] 下拉树 Ext.ux.ComboBoxTree 学习了不少东西,但和自己现用的TreeComboBox比较还是发现有些地方不妥,这里列出来大家探讨一下
1、xiexueze修改的下拉树每次展开时都会加载一次json,我测试的结果,不知道是不是我配置不当造成
2、tree貌似必须从外部传递进来,而tree在扩展内部实现
3、不是问题的问题,扩展定义了很多默认属性,修改了一些底层的方法
现在提出我的代码,其实也是ExtJS2.0的时候从其他地方学过来的,自己修改了一些代码,具体出处已经忘记了,如大家发现了请指出,谢谢
Ext.namespace("Ext.ux.form"); Ext.ux.form.TreeComboBox = Ext.extend(Ext.form.ComboBox, { initComponent : function(ct, position) { this.divId = 'tree-' + Ext.id(); if (isNaN(this.maxHeight)) this.maxHeight = 200; Ext.apply(this, { tpl : '<tpl>' + '<div style="height:' + this.maxHeight + 'px;">' + '<div id="' + this.divId + '"></div>' + '</div></tpl>' }); var root = new Ext.tree.AsyncTreeNode({ text : this.rootText, id : this.rootId, loader : new Ext.tree.TreeLoader({ dataUrl : this.treeUrl, clearOnLoad : true }) }); this.tree = new Ext.tree.TreePanel({ border : false, root : root, rootVisible : this.rootVisible, listeners : { scope : this, click : function(node) { this.setValue(node); this.collapse(); } } }); Ext.ux.form.TreeComboBox.superclass.initComponent.call(this); }, onRender : function(ct, position) { Ext.ux.form.TreeComboBox.superclass.onRender.call(this, ct, position); this.on("expand", function() { if (!this.tree.rendered) { this.tree.render(this.divId); } }, this) }, /*以下代码是为了将tree的node设置到combo中 因为我还有一些其他的作用,所以我是将这部分的代码重写到其他地方了 setValue : function(node) { if (typeof node == "object") { this.setRawValue(node.text); if (this.hiddenField) { this.hiddenField.value = node.id; } } else { this.setRawValue(node); } } */ }); Ext.reg('uxtreecombobox', Ext.ux.form.TreeComboBox);
之前的setValue我是直接覆盖了combo的方法
Ext.override(Ext.form.ComboBox, { setValue : function(node) { if (typeof node == "object") { // 当node为object对象时 node和tree里面的对应 this.lastSelectionText = node.text; // 设置显示文本为node的text this.setRawValue(node.text); if (this.hiddenField) { // 设置隐藏值为node的id this.hiddenField.value = node.id; } this.value = node.id; return this; } else { // 当node为文本时 这段代码是从combo的源码中拷贝过来的 具体作用不细说了 var text = node; if (this.valueField) { var r = this.findRecord(this.valueField, node); if (r) { text = r.data[this.displayField]; } else if (Ext.isDefined(this.valueNotFoundText)) { text = this.valueNotFoundText; } } this.lastSelectionText = text; if (this.hiddenField) { this.hiddenField.value = node; } Ext.form.ComboBox.superclass.setValue.call(this, text); this.value = node; return this; } } })
为什么要重写这个方法,请参考Ext.form.ComboBox加载json时刻默认选中的 ...
下面是使用的代码
xtype : 'uxtreecombobox', id : 'Ext.Strong.tyh.combo.yhBmid', hiddenName : 'yhBmid', fieldLabel : '${action.getText("YH_BM")}', editable : false, shadow : true, maxHeight : 200, mode : 'local', displayField : 'text', valueField : 'id', triggerAction : 'all', allowBlank : false, treeUrl : '<@s.url action="tbm_Shu_XianShi!json"/>', rootText : 'root', rootId : '0', // api里面的意思是 //【true to restrict the selected value to one of the values in the list, false to allow the user to set arbitrary text into the field (defaults to false)】 // 我的理解是combo中设置的值 // 能否为不在store中的内容 // 因为如果默认设置为false的时候每次在失去该combo对象的焦点时刻会触发一个事件重新设置一下value // 这个问题我解决了好久才搞定 forceSelection : true, rootVisible : false
为什么forceSelection : true,我们看一下源代码
beforeBlur : function(){ var val = this.getRawValue(), rec = this.findRecord(this.displayField, val); // 注意这里 如果rec不存在且forceSelection为true if(!rec && this.forceSelection){ if(val.length > 0 && val != this.emptyText){ this.el.dom.value = Ext.isDefined(this.lastSelectionText) ? this.lastSelectionText : ''; this.applyEmptyText(); }else{ this.clearValue(); } }else{ if(rec){ val = rec.get(this.valueField || this.displayField); } this.setValue(val); } },
总结一下,ExtJS的确实存在很多陷阱,很多简单的应用都必须从底层去解决,但是也提供了很好的学习机会,ExtJS的代码很多地方都值得我们去认真学习