2012-05-08 39 views
0

我的工作Ext.Button的延伸,使按钮的鼠标悬停/鼠标移出菜单的显示/隐藏。它正在为按钮的直接子菜单完美地工作,但是我遇到了一个问题,使其适用于任何二级/三级/ ect菜单。ExtJS的4.1“HoverButton”延长问题

现在,当用户在移动时项目中包含一个菜单顶部的菜单,它会打开菜单,用户可以将光标移动到它,没有任何问题,一切都将保持开放。如果用户然后将光标移出二级菜单进入开放空间,则所有菜单都将关闭,这也是正确的。但是,有时如果用户进入二级菜单,然后返回到其父菜单,则所有菜单将关闭,这不是应该发生的事情,至少光标所在的父菜单应保持打开状态。

从我的初步调试它看起来是与事件是如何激发一个问题,他们的时间。看起来,父菜单的mouseenter事件在从子菜单移回父菜单时不会触发。其次,它看起来像我的菜单mouseover事件不足够可靠地触发,足以让它在子菜单上的mouseleave事件触发后取消延迟隐藏任务。

演示的问题:http://qs1724.pair.com/users/autod1nx/EMPLOYEE/BDAMI/hoverbutton/index.html

而这里的代码,做任何事情根本性的错误脱颖而出?

Ext.define('Ext.HoverButton', {  
    extend: 'Ext.Button', 
    alias: 'widget.hoverButton', 
    isOver: false, 
    hideDelay: 250, 
    showDelay: 200, 

    applyListeners: function(menu, cfg) { 
     Ext.apply(menu, cfg); 
     Ext.each(menu.items, function(item, idx, allItems) { 
      if(item.menu) this.applyListeners(item.menu, cfg); 
     }, this); 
    }, 

    initComponent: function() { 
     var config = {}, 
      menuConfig = {}, 
      me = this; 

     me.delayedShowMenu = new Ext.util.DelayedTask(function() { 
      if(!me.isOver) return; 
      me.showMenu(); 
     }, this); 

     me.delayedHideMenu = new Ext.util.DelayedTask(function() { 
      if(me.isOver) return; 
      me.hideMenu(); 
     }); 

     if(Ext.isDefined(this.initialConfig.menu)) { 
      config = { 
       listeners: { 
        mouseover: { 
         scope: me, 
         fn: function(b) { 
          me.isOver = true; 
          me.delayedShowMenu.delay(me.showDelay); 
         } 
        }, 
        mouseout: { 
         scope: me, 
         fn: function(b) { 
          me.isOver = false; 
          me.delayedHideMenu.delay(me.hideDelay); 
         } 
        } 
       } 
      }; 

      menuConfig = { 
       listeners: { 
        mouseover: { 
         scope: me, 
         fn: function(menu, item, e) { 
          me.delayedHideMenu.cancel(); 
         } 
        }, 
        mouseenter: { 
         scope: me, 
         fn: function(menu, e) { 
          me.delayedHideMenu.cancel(); 
         } 
        }, 
        mouseleave: { 
         scope: me, 
         fn: function(menu, e) { 
          me.delayedHideMenu.delay(me.hideDelay); 
         } 
        } 
       } 
      }; 


      //apply mouseover/leave listeners to all submenus recursively 
      me.applyListeners(me.menu, menuConfig);  
     } 

     Ext.apply(me, Ext.apply(me.initialConfig, config)); 
     Ext.HoverButton.superclass.initComponent.apply(me, arguments); 
    } 
}); 
+0

您是否尝试过将'me.isOver = true/false'添加到menuConfig侦听器事件? –

+0

我有,似乎没有任何区别。经过更多的测试,看起来问题在于mouseover事件如何触发。在这种情况下,如果在离开子菜单时触发mouseleave事件之后并不是始终如一地或经常地触发delayedHideMenu上的.cancel()。 –

回答

1

我一直在做的东西有点类似,我已经采取了偷看http://www.quirksmode.org/dom/events/mouseover.html

看来,DOM的事件顺序应该是鼠标悬停后解决了问题 - >的mouseenter - >鼠标移开 - >这意味着有时会在delay()被设置之前调用cancel()。为了解决这个问题,我最后输入一个变量:

mouseenter: { 
scope: me, 
fn: function(menu, e) { 
    presentlyInside = menu; /* << */ 
    me.delayedHideMenu.cancel(); 
} 
}, 
mouseleave: { 
scope: me, 
fn: function(menu, e) { 
    if(presentlyInside==menu) /* << */ 
    me.delayedHideMenu.delay(me.hideDelay); 
} 
} 

希望它有帮助!

+0

有趣的是,自从我触及这段代码以来,它已经有一段时间了,但是一定会得到这个尝试。感谢您的回应! –

+0

我只在发布anwser之前几分钟才开始工作,但到目前为止在我的实现中(以及在Chrome上),我还没有发现任何故障。 –

+0

我知道这个回复非常迟到,但是我终于用你的修正更新了扩展,它就像一个冠军!再次感谢!! –

4

我发现这一个工程,也更简单。

Ext.define('Ext.HoverButton', { 
extend : 'Ext.Button', 
alias  : 'widget.hoverButton', 
listeners : { 
     mouseover : function() { 
      this.showMenu(); 
     }, 
     menushow : function() { 
      this.mouseLeaveMonitor = this.menu.el.monitorMouseLeave(100, this.hideMenu, this); 
     }, 
     destroy : function(combo) { 
      combo.menu.el.un(combo.mouseLeaveMonitor); 
     } 
    } 
});