哇,终于经过长时间的调试会话和测试各种方法后,我认识到问题不在于 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();
});
当然你可以使用一个全局变量来控制延迟时间。如果您想要更灵活的方法,您必须覆盖中的encodeScript
方法OverlayPanelRender
以传输附加属性。然后您可以使用_self.cfg.delay
. 请注意,您也必须替换组件模型OverlayPanel
,为其提供额外的属性。