`
literary_fly
  • 浏览: 90689 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

EXT中Menu和ComboBox的BUG及解决方法

阅读更多
最近一直在玩Ext,所以可能以后的东西会关于Ext的比较多。

刚开始的时候,觉得Ext真是相当的神奇,功能十分的强大。没想到新鲜感还没持续多久,问题就随之而来了。最近想要实现这么一个功能控件,就是类似ComboBox和DateField一样,可以点后面的箭头弹出一个小窗口里面设置一些信息,只不过要在弹出的一个小界面中可以放置文本框和ComboBox等许多的控件。

于是乎,想当然的找到Ext.form.ComboBox的源代码,按着我的要求改写,基本的思路就是把Ext.form.ComboBox中的list(DateView的实例)换成一个内嵌的panel,在panel里面显示需要显示的文本、checkbox等等的控件。经过一个上午的功夫,终于能够显示出界面来了,但是却碰到一个巨大的问题,只要一点击panel里面的控件,这个弹出的panel马上就自动隐藏了。再仔细Ext.form.ComboBox看看代码,里面确实强调了对控件的焦点的控制,是不能实现在弹出的panel里面再设置焦点的。

于是剩下最后的希望,即DateField了。先仔细的看了一下他的实现,这回用了个叫做Ext.menu.DateMenu的东西,而且居然是Ext.menu.Menu的子类。而在实际的操作上,一旦我们点击menu上的元素,menu是不会隐藏的,这个正适合我的要求。于是先构建我需要的panel(先在panel里放置了一个TextBox和CheckBox),然后再将其通过Ext.menu.Adapter包装成一个menu Item,再包装成一个menu,显示出来一看,居然还真就能编辑数据了。

但是接着又发现了一个问题,就是在panel中的控件一不注意就失去了焦点,没法输入了。仔细多试验了几下,发现在鼠标移动的时候,输入的焦点就自动跑开了,于是Ext.menu.Menu的源代码里面发现,其在onMouseOver函数中要根据当前的位置设置选中的MenuItem,这当然就要转移焦点了,于是简单的将生成的menu的实例的onMouseOver设置成Ext.emptyFn。再一实验就ok了。

接着我又换了一个comboBox的控件,这下又出问题了。一点Panel里面的ComboBox空间的下拉按钮,弹不出列表选择框了。刚开始我还以为是数据出问题了,换了N中写法那个列表还是不出来。突然脑子一闪,心想是不是comboBox的list的z-index属性值比menu的小导致的呢?于是加长了comboBox的列表的数据,终于在panel之外露出了list的尾巴。我晕,只有把list的z-index加大了。还好comboBox提供了listClass配置项用于自定义class,于是写了个只有z-index属性的class,放进去,居然这下就能显示出来了。接着试,居然还有问题,一选中comboBox的数据项的时候,居然外面这个panel自己先隐藏了,这下又没法编辑数据了。看来Ext的作者也没预想到我会又这么变态的做法吧。又研究了半天,最终通过调试的时候发现在点击comboBox中的list数据的时候,会触发Ext.menu.MenuMgr中的一个onMouseDown,这里面判断如果点的不是当前显示的menu的内容,就把当前menu隐藏掉。原来Ext中,应用程序只能有一个当前的活动的menu的,这个是通过Ext.menu.MenuMgr来管理活动的menu的实例的。在Ext.menu.MenuMgr中注册了一个对document的mousedown事件的监视,handler就是onMouseDown方法。于是乎首先想到的还是hook方法,就是想办法把阻碍我们办事的方法改成我们需要的样子,整了半天,发现效果也不尽如意,差点就要放弃了。

又细看了一下onMouseDown方法的实现,其实现如下:

function onMouseDown(e){
       if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
           hideAll();
       }
   }

后面的e.getTarget(".x-menu")就是一个为了发现当前的事件的触发元素的父元素及祖先元素是不是包含了有x-menu这个class的,如果有就跳过不处理,否则就隐藏menu。那我们是不是把combox的listClass里加上x-menu这个class就ok了呢?一试之后,居然还真就好使了,惊叹有些复杂的东西还是有简单的解决的。

后记:这一天的琢磨,个人觉得Ext应该说还是不是足够成熟。既然提供了Ext.menu.Adapter这种包装类,但是却不能支持在menu里面放置comboBox,这也该是传说中的Bug吧。下面是示例的代码,供有缘的同志参考:

actions.template.DataTypeSettingControl = Ext.extend(Ext.form.TriggerField,{

onTriggerClick : function(){
        if(this.disabled){return;}       
        if(!this.menu ){
            this.menu = new Ext.menu.Menu({});           
            this.menu.onMouseOver=Ext.emptyFn;

            var panel = this;
          
            this.viewPanel = new Ext.Panel({
             layout:"form",
             border:false,
             width:width,
             height:height,
             items:[new Ext.form.ComboBox({listClass:"toppest_list x-menu",
             store:['yyyy','MM'],fieldLabel:'日期格式'})],
             buttons:[{text:"确定",handler:function(){
     value ="";
     for(var i =0; i<panel.viewPanel.items.getCount();i++){
      value +="," + panel.viewPanel.items.get(i).getValue();
     }
     panel.setValue(value);
     panel.menu.destroy();
     delete panel.menu;
    }},{text:"取消",handler:function(){
     panel.menu.destroy();
     delete panel.menu;
    }}]
            });
            this.viewPanel.on("render", function(viewPanel){
          viewPanel.getEl().swallowEvent("click");
          viewPanel.container.addClass("x-menu-date-item");
      });
   var di = new Ext.menu.Adapter(this.viewPanel,{});
   this.menu.add(di);
   this.menu.relayEvents(di, ["select"]);
        }

        this.menu.show(this.el, "tl-bl?");
    }

}



其中toppest_list的定义如下:

.toppest_list{
z-index: 1000000;
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics