extjs是一个非常不错的页面显示架构,在扩展页面组件方面也是十分的灵活方便的,我们在项目中有遇到需要在下拉框中显示树形数据供用户单选或者多选的请款,所以我就扩展了其之前的下拉框控件 Ext.form.TriggerField
Ext.ns("Fairies.form"); //支持显示树的下拉选择框 Fairies.form.TreeCombo=Ext.extend(Ext.form.TriggerField,{ defaultAutoCreate:{tag: "input", type: "text", size: "24", autocomplete: "off"}, shadow:'sides', maxHeight: 300, hideTrigger:false, rootVisible:true, resizable:true, minListWidth:70, handleHeight:8, editable:false, lazyInit:true, initComponent:function(){ Fairies.form.TreeCombo.superclass.initComponent.call(this); this.addEvents('expend','collapse','select'); }, onRender:function(ct, position){ Fairies.form.TreeCombo.superclass.onRender.call(this, ct, position); if(this.hiddenName){ this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},'before', true); this.hiddenField.value = this.hiddenValue !== undefined ? this.hiddenValue : this.value !== undefined ? this.value : ''; this.el.dom.removeAttribute('name'); } this.el.dom.setAttribute('readOnly', true); this.el.on('mousedown', this.onTriggerClick, this); this.el.addClass('x-combo-noedit'); this.initTreeLayer(); }, initTreeLayer:function(){ if(!this.treeLayer){ var cls='x-combo-list'; this.list = new Ext.Layer({ shadow: this.shadow, cls: [cls].join(' '), constrain:false }); var lw = this.listWidth || Math.max(this.wrap.getWidth()-this.trigger.getWidth(), this.minListWidth); this.list.setWidth(lw); this.list.swallowEvent('mousewheel'); this.assetHeight = 0; this.view=new Ext.tree.TreePanel({ applyTo:this.list, autoScroll:true, checkModel:this.checkModel, onlyLeafCheckable:false, animate:true, height:100, rootVisible:this.rootVisible, containerScroll: true, loader:new Ext.tree.TreeLoader({ dataUrl:this.dataUrl, baseAttrs:this.checkModel&&this.checkModel=='cascade'?{uiProvider:Ext.tree.TreeCheckNodeUI}:null }), root:new Ext.tree.AsyncTreeNode({id:'0'}) }); this.view.on('click',this.onViewClick,this); this.view.on('checkchange',this.onCheckChange,this); this.resizer=new Ext.Resizable(this.list,{ pinned:true, handles:'se' }); this.resizer.on('resize',function(r,w,h){ this.view.setHeight(h-this.handleHeight); },this); } }, onTriggerClick : function(){ if(this.disabled){ return; } if(this.isExpanded()){ this.collapse(); this.el.focus(); }else { this.onFocus({}); this.expand(); this.el.focus(); } }, onViewClick : function(doFocus){ var node=this.view.getSelectionModel().getSelectedNode(); if (this.checkModel&&this.checkModel=='cascade'){//只针对单选和级联多选的处理 this.setValue(this.view.getChecked('id')); this.collapse(); this.fireEvent('select',this,node); }else{ if(node){ this.onSelect(node); } if(doFocus !== false){ this.el.focus(); } } }, onSelect : function(node){ this.setValue(node.id); this.collapse(); this.fireEvent('select', this, node); }, setValue : function(id){ if (this.checkModel&&this.checkModel=='cascade'){//只针对单选和级联多选的处理 this.view.getRootNode().expand(true); if (id.indexOf(',')!=-1) id=id.split(','); var text=''; this.view.checkModel='multiple'; var ids=this.view.getChecked('id'); for (i=0;i<ids.length;i++){ var node=this.view.nodeHash[ids[i]]?this.view.nodeHash[ids[i]]:null; if (node){node.checked=false;node.getUI().check(false)} } for (i=0;i<id.length;i++){ var node=this.view.nodeHash[id[i]]?this.view.nodeHash[id[i]]:null; text+=node?node.text+',':''; if (node){node.checked=true;node.getUI().check(true)} } this.view.checkModel=this.checkModel; this.hiddenField.value=id; Fairies.form.TreeCombo.superclass.setValue.call(this,text?text:''); }else{ this.view.getRootNode().expand(true); var node = this.view.nodeHash[id]; this.hiddenField.value=id; Fairies.form.TreeCombo.superclass.setValue.call(this, node?node.text:''); } }, onCheckChange:function(node){ if (this.checkModel&&this.checkModel=='cascade'){//只针对单选和级联多选的处理 this.setValue(this.view.getChecked('id')); } }, isExpanded : function(){ return this.list && this.list.isVisible(); }, expand : function(){ if(this.isExpanded() || !this.hasFocus){ return; } this.list.alignTo(this.wrap, this.listAlign); this.list.show(); var zindex = Ext.WindowMgr.zseed + 5000; this.list.setStyle("z-index", zindex.toString()); Ext.getDoc().on('mousewheel', this.collapseIf, this); Ext.getDoc().on('mousedown', this.collapseIf, this); this.fireEvent('expand', this); }, collapse : function(){ if(!this.isExpanded()){ return; } this.list.hide(); Ext.getDoc().un('mousewheel', this.collapseIf, this); Ext.getDoc().un('mousedown', this.collapseIf, this); this.fireEvent('collapse', this); }, collapseIf : function(e){ if(!e.within(this.wrap) && !e.within(this.list)){ this.collapse(); } }, clearValue : function(){ if(this.hiddenField){ this.hiddenField.value = ''; } setValue(''); this.applyEmptyText(); }, onDestroy : function(){ if(this.view){ this.view.el.removeAllListeners(); this.view.el.remove(); this.view.purgeListeners(); } if(this.list){ this.list.destroy(); } Fairies.form.TreeCombo.superclass.onDestroy.call(this); }, getValue : function(){ if(this.valueField){ return typeof this.value != 'undefined' ? this.value : ''; }else{ return Fairies.form.TreeCombo.superclass.getValue.call(this); } } }); Ext.reg('treeCombo', Fairies.form.TreeCombo);
调用方式:
,{fieldLabel:'用户功能角色', typeAhead : true, mode:'local', triggerAction : 'all', emptyText:'请选择功能角色', selectOnFocus : true, valueField:'id', displayField:'text', hiddenName:'funcRoles', dataUrl:'rbac/function/queryFunRoleManagerDate.action?org_id='+Fairies.userConfig.upperOrgId, checkModel:'cascade',//single,cascade xtype:'treeCombo', allowBlank:false, rootVisible:false, width:250 }
显示结果: