扩展Ext的Combobox实现多选下拉列表

使用过Ext的人都知道,Ext的Combobox只支持单项选择,而项目中我们经常用到多选下拉框,怎么做呢?

很简单,因为Ext给我们提供了继承机制,这也意味着我们可以通过继承Combobox的方式来重写下拉列表的实现,达到多选的目的!

经过查看Combobox的源码我们发现,Combobox的下拉列表是由DataView类来实现的,那么,我们开始大胆的想:我们直接用一个带CheckBox的GridPanal来代替DataView实现可以吗?

OK,当然可以!我自己研究了一下,写了个代码,基本可以实现下拉框多选了:

[javascript] view plain copy
  1. Ext.form.MultiSelect = Ext.extend(Ext.form.ComboBox, {  
  2.     // 使用积极的初始化模式  
  3.     lazyInit : false,  
  4.     headerText : "EMPTY",  
  5.     resetText : "EMPTY",  
  6.     sureText : "EMPTY",  
  7.     textValue : "",  
  8.     maxHeight : 310,  
  9.     beforeSelect : null,  
  10.     /** 
  11.      * 初始化下拉列表 原来的下拉列表使用DataView类来实现,现在改为使用GridPanel来实现,这样更方便于多选操作 
  12.      */  
  13.     initList : function()  
  14.     {  
  15.         if (!this.list)  
  16.         {  
  17.             var cls = 'x-combo-list';  
  18.             this.list = new Ext.Layer( {  
  19.                 shadow : this.shadow,  
  20.                 cls : [ cls, this.listClass ].join(' '),  
  21.                 constrain : false  
  22.             });  
  23.   
  24.             var lw = this.listWidth  
  25.                     || Math.max(this.wrap.getWidth(), this.minListWidth);  
  26.             this.list.setWidth(lw);  
  27.             this.assetHeight = 0;  
  28.   
  29.             if (this.title)  
  30.             {  
  31.                 this.header = this.list.createChild( {  
  32.                     cls : cls + '-hd',  
  33.                     html : this.title  
  34.                 });  
  35.                 this.assetHeight += this.header.getHeight();  
  36.             }  
  37.   
  38.             this.innerList = this.list.createChild( {  
  39.                 cls : cls + '-inner'  
  40.             });  
  41.             this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));  
  42.   
  43.             var sm = new Ext.grid.CheckboxSelectionModel();  
  44.             var all = this;  
  45.             var ht = this.headerText == "EMPTY" ? "选择项目" : this.headerText;  
  46.             var rt = this.resetText == "EMPTY" ? "重置" : this.resetText;  
  47.             var st = this.sureText == "EMPTY" ? "确定" : this.sureText;  
  48.             this.view = new Ext.grid.GridPanel( {  
  49.                 store : this.store,  
  50.                 hideHeaders : true,  
  51.                 applyTo : this.innerList,  
  52.                 columns : [ sm, {  
  53.                     header : ht,  
  54.                     sortable : false,  
  55.                     dataIndex : this.displayField  
  56.                 } ],  
  57.                 viewConfig : {  
  58.                     forceFit : true  
  59.                 },  
  60.                 autoScroll : true,  
  61.                 width : this.list.getWidth(),  
  62.                 sm : sm,  
  63.                 tbar : new Ext.PagingToolbar({ pageSize: this.pageSize, store:this.store}),  
  64.                 bbar : [ {  
  65.                     xtype : "button",  
  66.                     text : rt,  
  67.                     handler : function()  
  68.                     {  
  69.                         all.onReset();  
  70.                     }  
  71.                 }, "-", {  
  72.                     xtype : "button",  
  73.                     text : st,  
  74.                     handler : function()  
  75.                     {  
  76.                         all.onSure();  
  77.                     }  
  78.                 } ],  
  79.                 iconCls : 'icon-grid'  
  80.             });  
  81.   
  82.             // 设置下拉列表的高度,如果超过了最大高度则使用最大高度  
  83.             if (this.view.getSize().height > this.maxHeight)  
  84.             {  
  85.                 this.view.setHeight(this.maxHeight);  
  86.             }  
  87.   
  88.             // 如果设置了默认值,则在下拉列表中回显  
  89.             if (this.value)  
  90.             {  
  91.                 this.setValue(this.value);  
  92.             }  
  93.   
  94.             if (this.pageSize)  
  95.             {  
  96.                 /* 
  97.                  * var pageBar = new Ext.PagingToolbar({ pageSize: 15, store: 
  98.                  * this.view.getStore(), displayInfo: true }); 
  99.                  * this.view.add(pageBar); this.view.doLayout(); 
  100.                  */  
  101.             }  
  102.   
  103.             if (this.resizable)  
  104.             {  
  105.                 this.resizer = new Ext.Resizable(this.list, {  
  106.                     pinned : true,  
  107.                     handles : 'se'  
  108.                 });  
  109.                 this.resizer.on('resize'function(r, w, h)  
  110.                 {  
  111.                     this.maxHeight = h - this.handleHeight  
  112.                             - this.list.getFrameWidth('tb') - this.assetHeight;  
  113.                     this.listWidth = w;  
  114.                     this.innerList.setWidth(w - this.list.getFrameWidth('lr'));  
  115.                     this.restrictHeight();  
  116.                 }, this);  
  117.                 this[this.pageSize ? 'footer' : 'innerList'].setStyle(  
  118.                         'margin-bottom'this.handleHeight + 'px');  
  119.             }  
  120.         }  
  121.     },  
  122.     /** 
  123.      * 确定选择事件 
  124.      */  
  125.     onSure : function()  
  126.     {  
  127.         var selecteds = this.view.getSelectionModel().getSelections();  
  128.         var value = [];  
  129.         var all = this;  
  130.         var tv = [];  
  131.         Ext.each(selecteds, function(rc)  
  132.         {  
  133.             value.push(rc.data[all.valueField]);  
  134.             tv.push(rc.data[all.displayField]);  
  135.         });  
  136.         this.textValue = tv.join();  
  137.         var valueStr = value.join();  
  138.         beforeSelect = this.beforeSelect;  
  139.         if(typeof beforeSelect == 'function')  
  140.         {  
  141.             if(!beforeSelect(valueStr))  
  142.             {  
  143.                 this.collapse();  
  144.                 return;  
  145.             }  
  146.         }  
  147.         this.setValue(valueStr);  
  148.         this.value = value.join();  
  149.         this.collapse();  
  150.     },  
  151.       
  152.     getTextValue : function(){  
  153.         return this.textValue;  
  154.     },  
  155.     /** 
  156.      * 重置事件 
  157.      */  
  158.     onReset : function()  
  159.     {  
  160.         this.view.getSelectionModel().clearSelections();  
  161.     },  
  162.     /** 
  163.      * 给ComboBox设置值  
  164.      * 设置完全局的值后,再在下拉列表中回显这些值 
  165.      */  
  166.     setValue : function(v)  
  167.     {  
  168.         var text = v;  
  169.         var ta = [];  
  170.         // 根据值查找出名称,并组装显示  
  171.         if (this.valueField && v && ("" + v).length > 0)  
  172.         {  
  173.             var sv = ("" + v).split(",");  
  174.             for ( var i = 0; i < sv.length; i++)  
  175.             {  
  176.                 var r = this.findRecord(this.valueField, sv[i]);  
  177.                 if (r)  
  178.                 {  
  179.                     ta.push(r.data[this.displayField]);  
  180.                 }  
  181.                 else if (this.valueNotFoundText !== undefined)  
  182.                 {  
  183.                     ta.push(this.valueNotFoundText);  
  184.                 }  
  185.             }  
  186.             text = ta.join();  
  187.         }  
  188.         this.lastSelectionText = ta.join();  
  189.         if (this.hiddenField)  
  190.         {  
  191.             this.hiddenField.value = v;  
  192.         }  
  193.         this.textValue = text;  
  194.         Ext.form.ComboBox.superclass.setValue.call(this, text);  
  195.         this.value = v;  
  196.         // 在下拉列表中回显设置的值  
  197.         if (this.view && v && ("" + v).length > 0)  
  198.         {  
  199.             var sv = ("" + v).split(",");  
  200.             var mv = this.view;  
  201.             var sr = [];  
  202.             var all = this;  
  203.             this.store.each(function(item)  
  204.             {  
  205.                 for ( var i = 0; i < sv.length; i++)  
  206.                 {  
  207.                     if (sv[i] == item.data[all.valueField])  
  208.                     {  
  209.                         sr.push(item);  
  210.                         break;  
  211.                     }  
  212.                 }  
  213.             });  
  214.             this.view.getSelectionModel().selectRecords(sr);  
  215.         }  
  216.     },  
  217.     /** 
  218.      * 触发下拉列表展现 这里不使用ComboBox的查询功能,直接展现 
  219.      */  
  220.     onTriggerClick : function()  
  221.     {  
  222.         if (this.disabled)  
  223.         {  
  224.             return;  
  225.         }  
  226.         if (this.isExpanded())  
  227.         {  
  228.             this.collapse();  
  229.         }  
  230.         else  
  231.         {  
  232.             this.onFocus( {});  
  233.             this.expand();  
  234.             this.el.focus();  
  235.         }  
  236.     }  
  237. });  


怎么使用呢?看看这个使用的例子吧:

[html] view plain copy
  1. <html>  
  2. <head>  
  3. <script type="text/javascript" src="./ext-2.0.2/adapter/ext/ext-base.js">script>  
  4. <script type="text/javascript" src="./ext-2.0.2/ext-all.js">script>  
  5. <script type="text/javascript" src="./MultiCombo.js">script>  
  6. <link rel="stylesheet" type="text/css"  
  7.     href="./ext-2.0.2/resources/css/ext-all.css" />  
  8. head>  
  9. <body>  
  10. <button onclick="showMenu(this)" id="heare">显示值button>  
  11. <div id="local-states">div>  
  12. body>  
  13. <script>  
  14. var store = new Ext.data.SimpleStore({  
  15.    fields : ['id', 'text'],  
  16.    data : [['1', '一月'], ['2', '三月'], ['3', '二月'], ['4', '四月'],  
  17.      ['5', '五月'], ['6', '六月'], ['7', '七月'], ['8', '八月'],['9', '九月'], ['10', '十月'], ['11', '十一月'], ['12', '十二月'],['13', '十三月'], ['14', '十四月'], ['15', '十五月']]  
  18. });  
  19.   
  20. var combo = new Ext.form.MultiSelect({  
  21.    id : 'myCombo',  
  22.    name : 'name',  
  23.    hiddenName : 'id',  
  24.    store : store,  
  25.    emptyText : '请选择...',  
  26.    mode : 'local',  
  27.    value : '5,6,7',  
  28.    triggerAction : 'all',  
  29.    valueField : 'id',  
  30.    displayField : 'text',  
  31.    editable : false,  
  32.    pageSize : 5,  
  33.    beforeSelect : function(selectValues){  
  34.         if(selectValues == '5')  
  35.         {  
  36.             return true;  
  37.         }  
  38.         else{  
  39.             Ext.Msg.alert("alert", "Can not!");  
  40.             return false;  
  41.         }  
  42.    },  
  43.    blankText : '请选择...'  
  44. });  
  45. combo.render("local-states");  
  46.   
  47. function showMenu(){  
  48.     alert(combo.getValue());  
  49. }  
  50. script>  
  51. html>  

OK,目标达到!细心的朋友会发现,这个多选下拉列表使用的就是GridPanel实现的,而GirdPanel是可以支持分页的,那么我们可不以可以搞分页呢?肯定是可以的,但是经过我试了之后发现,加上分页控件后下拉列表展现变得非常难看,这个问题还是留给朋友们实现吧,呵呵可……

由于注册未满一周,不能上传效果图,大家还是拷贝源码下去自己运行吧……


你可能感兴趣的:(javascript)