2012-08-10 126 views
7

我使用jsf 2和glassfish 3.1.2的Primefaces 3.2。Primefaces overlayPanel的延遲問題 - 加載到懶惰

我有一個包含用戶頭像的用戶的p:dataTable。每當用戶頭像AP移動鼠標:overlayPanel出現更多的信息,對用戶(延遲加載),而當用戶移動鼠標移開消失 - 這樣的:

<p:overlayPanel for="avatar" dynamic="true" showEvent="mouseover" hideEvent="mouseout" ...>

這工作得很好 - 只要用戶是「緩慢」的。每當用戶將光標移動到許多頭像的上方時,許多疊加面板都將保持可見狀態。 例如,當用戶將光標放在顯示用戶頭像的位置上時,並使用鼠標的滾輪向下或向上滾動該使用者。

我認爲overlaypanel開始動態加載信息(dynamic="true"),當showEvent="mouseover"被調度時,並在服務器響應到達後顯示overlaypanel。 通過這種方式,當覆蓋面板變得可見時,無法檢測光標是否已經離開 - 所以hideEvent="mouseout"從不分派。

有沒有辦法讓primefaces overlaypanel直接出現在mousover上,顯示加載gif並在響應來自服務器時將內容更新到overlaypanel中。

這是一個很好的方法,還是有人知道任何其他方式來解決這個討厭的問題?

感謝皮特

+0

你確實很幸運能夠獲得內容。雖然即時通訊遇到完全相同的問題,但我的內容也完全沒有。即使是一個簡單的h:outputText,沒有引用實際的行模型(你用var指定的那個模型)也不會顯示。令人遺憾的是,來自primefaces的開發人員甚至沒有考慮過一個非常常見的企業問題(IMO認爲p:overlayPanel或p:tooltip沒有被設計用於表格)。 – Paranaix 2012-08-14 13:58:06

+0

你用螢火蟲測試過工作流程嗎?檢查JS錯誤,同時檢查來自服務器的ajax響應的內容。 – 2012-08-14 14:12:31

+0

是的,發送ajax請求。它真的很奇怪;雖然我沒有使用3.3,但最新的3.4快照。這可能是一個新的錯誤。 – Paranaix 2012-08-14 14:27:23

回答

4

由於我的第一個答案已經很長,並且包含有效的信息,我決定打開一個新的答案來展示我的最終方法。

我現在使用Primefaces繼承模式,使代碼更清潔。另外我注意到,替換/覆蓋整個bindEvents函數並不是必需的,因爲我們可以刪除舊的事件處理程序。最後,這段代碼修復了最近遇到的問題:ajax到達之前的隱藏事件。

PrimeFaces.widget.OverlayPanel = PrimeFaces.widget.OverlayPanel 
     .extend({ 

      bindEvents : function() { 
       this._super(); 

       var showEvent = this.cfg.showEvent + '.ui-overlay', hideEvent = this.cfg.hideEvent 
         + '.ui-overlay'; 

       $(document).off(showEvent + ' ' + hideEvent, this.targetId).on(
         showEvent, this.targetId, this, function(e) { 
          var _self = e.data; 

          clearTimeout(_self.timer); 
          _self.timer = setTimeout(function() { 
           _self.hidden = false; 
           _self.show(); 
          }, 300); 
         }).on(hideEvent, this.targetId, this, function(e) { 
        var _self = e.data; 

        clearTimeout(_self.timer); 
        _self.hidden = true; 
        _self.hide(); 

       }); 
      }, 

      _show : function() { 
       if (!this.cfg.dynamic || !this.hidden) { 
        this._super(); 
       } 
      } 

     }); 

對不起窮人格式:日食故障;)

2

哇,終於長調試運行會議結束後和測試各種方法我認識到這個問題的心不是Ajax請求,但該事件處理程序本身:

.on(hideEvent, this.targetId, this, function(e) { 
      var _self = e.data; 

      if(_self.isVisible()) { 
       _self.hide(); 
      } 
     }); 

正如你所看到的,小部件只是隱藏,如果它之前可見。如果你移動你的鼠標進行得太快,現在有兩種情況:

  • 小部件的心不是在所有
  • 動畫可見

仍然會在這種情況下,事件被丟棄,面板保持可見。當動畫排隊時,只需刪除if語句即可解決問題。我這樣做是通過更換整個bindEvents方法:

PrimeFaces.widget.OverlayPanel.prototype.bindEvents = function() { 
    //mark target and descandants of target as a trigger for a primefaces overlay 
    this.target.data('primefaces-overlay-target', this.id).find('*').data('primefaces-overlay-target', this.id); 

    //show and hide events for target 
    if(this.cfg.showEvent == this.cfg.hideEvent) { 
     var event = this.cfg.showEvent; 

     $(document).off(event, this.targetId).on(event, this.targetId, this, function(e) { 
      e.data.toggle(); 
     }); 
    } 
    else { 
     var showEvent = this.cfg.showEvent + '.ui-overlay', 
     hideEvent = this.cfg.hideEvent + '.ui-overlay'; 

     $(document).off(showEvent + ' ' + hideEvent, this.targetId).on(showEvent, this.targetId, this, function(e) { 
      var _self = e.data; 

      if(!_self.isVisible()) { 
       _self.show(); 
      } 
     }) 
     .on(hideEvent, this.targetId, this, function(e) { 
      var _self = e.data; 

      _self.hide(); 

     }); 
    } 

    //enter key support for mousedown event 
    this.bindKeyEvents(); 

    var _self = this; 

    //hide overlay when mousedown is at outside of overlay 
    $(document.body).bind('mousedown.ui-overlay', function (e) { 
     if(_self.jq.hasClass('ui-overlay-hidden')) { 
      return; 
     } 

     //do nothing on target mousedown 
     var target = $(e.target); 
     if(_self.target.is(target)||_self.target.has(target).length > 0) { 
      return; 
     } 

     //hide overlay if mousedown is on outside 
     var offset = _self.jq.offset(); 
     if(e.pageX < offset.left || 
      e.pageX > offset.left + _self.jq.outerWidth() || 
      e.pageY < offset.top || 
      e.pageY > offset.top + _self.jq.outerHeight()) { 

      _self.hide(); 
     } 
    }); 

    //Hide overlay on resize 
    var resizeNS = 'resize.' + this.id; 
    $(window).unbind(resizeNS).bind(resizeNS, function() { 
     if(_self.jq.hasClass('ui-overlay-visible')) { 
      _self.hide(); 
     } 
    }); 
}; 

負載執行這個代碼和問題應消失。



當您更換js代碼不過,你可以用這個機會來實現相當不錯的功能。通過在事件處理程序使用超時一個可以輕鬆實現一點點延遲不只是提高了可用性(沒有更多的成千上萬的彈出窗口的出現),而且還降低了網絡流量:

 $(document).off(showEvent + ' ' + hideEvent, this.targetId).on(showEvent, this.targetId, this, function(e) { 
      var _self = e.data; 

      _self.timer = setTimeout(function(){ 
       if(!_self.isVisible()) { 
        _self.show(); 
       } 
      }, 300); 
     }) 
     .on(hideEvent, this.targetId, this, function(e) { 
      var _self = e.data; 

      clearTimeout(_self.timer); 
      _self.hide(); 

     }); 

Ofcourse,你可以使用全局變量來控制延誤時間。如果您想要更靈活的方法,則必須覆蓋OverlayPanelRender中的encodeScript方法以傳輸其他屬性。您可以通過_self.cfg.delay訪問它。但請注意,您必須替換組件型號OverlayPanel,並提供額外的屬性。

+0

聽起來好不好,謝謝你的努力。我會檢查一下,稍後再回來。 – 2012-08-15 09:38:48

+0

您是否使用Primefaces 3.3或3.4的快照?我目前正在考慮使用3.4的快照將您的想法/更改修改爲Primefaces 3.2 – 2012-08-15 12:11:22

+0

Im。我認爲它從10.8開始;即時通訊不太確定。 3.3版本中遇到的一些錯誤是通過更新修復的。最值得注意的可能是p:menuitem中的f:param支持。 – Paranaix 2012-08-15 12:31:39

2

同時我要感謝你爲這個輝煌的解決方案,我藉此機會更新它Primefaces 5.2。在我們的應用程序中,代碼在升級後壞掉了。

遵循Primefaces 5.2更新的代碼:

PrimeFaces.widget.OverlayPanel.prototype.bindTargetEvents = function() { 
    var $this = this; 
    //mark target and descandants of target as a trigger for a primefaces overlay 
    this.target.data('primefaces-overlay-target', this.id).find('*').data('primefaces-overlay-target', this.id); 

    //show and hide events for target 
    if(this.cfg.showEvent === this.cfg.hideEvent) { 
     var event = this.cfg.showEvent; 

     this.target.on(event, function(e) { 
      $this.toggle(); 
     }); 
    } 
    else { 
     var showEvent = this.cfg.showEvent + '.ui-overlaypanel', 
     hideEvent = this.cfg.hideEvent + '.ui-overlaypanel'; 

     this.target 
      .off(showEvent + ' ' + hideEvent) 
      .on(showEvent, function(e) { 
       clearTimeout($this.timer); 

       $this.timer = setTimeout(function() { 
        $('.ui-overlaypanel').hide(); 
        $this.hidden = false; 
        $this.show(); 
       }, 500); 
      }) 
      .on(hideEvent, function(e) { 

       clearTimeout($this.timer); 

       $this.timer = setTimeout(function() { 
        // don't hide if hovering overlay 
        if(! $this.jq.is(":hover")) { 
         $this.hide(); 
        } 
       }, 100); 
      }); 
    } 

    $this.target.off('keydown.ui-overlaypanel keyup.ui-overlaypanel').on('keydown.ui-overlaypanel', function(e) { 
     var keyCode = $.ui.keyCode, key = e.which; 

     if(key === keyCode.ENTER||key === keyCode.NUMPAD_ENTER) { 
      e.preventDefault(); 
     } 
    }) 
    .on('keyup.ui-overlaypanel', function(e) { 
     var keyCode = $.ui.keyCode, key = e.which; 

     if(key === keyCode.ENTER||key === keyCode.NUMPAD_ENTER) { 
      $this.toggle(); 
      e.preventDefault(); 
     } 
    }); 
}; 

我還添加了一個額外的功能,它允許用戶將鼠標移動到覆蓋而不隱藏它。它應該隱藏,當你移動鼠標,然後我通過它完成:

<p:overlayPanel .... onShow="onShowOverlayPanel(this)" ...> 

function onShowOverlayPanel(ovr) { 
    ovr.jq.on("mouseleave", function(e) { 
     ovr.jq.hide(); 
    }); 
} 

希望你喜歡!