我使用的是Primefaces 3.2和jsf 2以及glassfish 3.1.2。
我有一个p:dataTable用户包含用户的头像。每当用户将鼠标移动到头像上时,p:overlayPanel会在用户上显示更多信息(延迟加载),并在用户将光标移开时消失 - 如下所示:
<p:overlayPanel for="avatar" dynamic="true" showEvent="mouseover" hideEvent="mouseout" ...>
这非常有效 - 只要用户“慢速”。每当用户将光标快速移动到许多化身上方时,许多overlayPanel都会保持可见。 例如,当用户将光标悬停在显示用户头像的位置时,并使用鼠标滚轮向下或向上滚动用户。
我相信在调度dynamic="true"
时,overlaypanel会从服务器动态加载信息(showEvent="mouseover"
),并在服务器响应到达后显示overlaypanel。
这样,当overlaypanel变得可见时,无法检测光标是否已经离开 - 因此永远不会调度hideEvent="mouseout"
。
有没有办法让primefaces overlaypanel直接显示在mousover上,显示加载gif并在响应来自服务器时将内容更新到overlaypanel。
这是一个很好的appraoch还是有人知道解决这个令人讨厌的问题的其他方法吗?
谢谢皮特
答案 0 :(得分:5)
由于我的第一个答案已经很长并且包含有效信息,我决定打开一个新的答案,展示我的最终方法。
我现在使用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();
}
}
});
我很抱歉格式不佳:日食错误;)
答案 1 :(得分:2)
.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();
});
当然,您可以使用全局变量来控制延迟时间。如果您想要更灵活的方法,则必须覆盖encodeScript
中的OverlayPanelRender
方法以传输其他属性。您可以使用_self.cfg.delay
访问它。请注意,您还必须替换组件模型OverlayPanel
,同时为其提供额外的属性。
答案 2 :(得分: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();
});
}
希望你喜欢!
答案 3 :(得分:0)
已经很长时间了,但是如果有人碰到这个问题,可以在showDelay
中添加一个overlayPanel
属性来解决此问题starting from Primefaces 6.2。但是,由于某种原因,它不在官方文档中。