2012-05-08 101 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); 
     } 
    } 
});