2012-05-08 5 views
0

Я работаю над расширением Ext.Button, которое позволяет отображать/скрывать меню кнопки мыши на мыши/мыши. Он отлично работает для непосредственного дочернего меню кнопки, однако я столкнулся с проблемой, когда он корректно ведет себя для любых вспомогательных/третичных/ect-меню.ExtJS 4.1 «HoverButton» вопрос расширения

Прямо сейчас, когда пользователь перемещает элемент am в верхнем меню, содержащем меню, он откроет меню, и пользователь может без проблем переместить курсор в него, все останется открытым. Если пользователь затем перемещает курсор из вторичного меню в открытое пространство, все меню закроют, что тоже правильно. НО, иногда, если пользователь переходит во вторичное меню, а затем возвращается в свое родительское меню, все меню закрываются, что не должно произойти, по крайней мере, что родительское меню, в котором находится курсор, должно оставаться открытым ,

С моей начальной отладки это выглядит как проблема с тем, как стреляют события, и их время. Похоже, что событие 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 listener events? –

+0

У меня есть да, похоже, не имеет никакого значения. После большего тестирования похоже, что проблема заключается в том, как запускается событие mouseover. В этом случае не запускается последовательно или достаточно часто, чтобы вызывать .cancel() на delayedHideMenu после того, как событие mouseleave срабатывает при выходе из подменю. –

ответ

1

Я делал что-то подобное немного, и я решил проблему после того, взглянуть на http://www.quirksmode.org/dom/events/mouseover.html

кажется, что порядок событий DOM должен быть Mouseover -> MouseEnter -> MouseOut -> mouseleave, что означает, что иногда cancel() будет вызываться до того, как будет установлена ​​delay(). Чтобы решить проблему, я сохраняю последнее значение в переменной:

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

У меня есть работа за несколько минут до публикации андерсера, но до сих пор в моей реализации (и в 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); 
     } 
    } 
}); 
Смежные вопросы