英文:
Event handler not working on dynamic content even with event delegation
问题
I have two ModalPopups
The first one opens and has a Tooltip text that the user can view for more detail with the "mouseenter" event listener.
Once the user clicks to close the modal through one of three buttons, the second ModalPopup opens with another Tooltip text. The Tooltip text on "mouseenter" does not work in this second ModalPopup.
This is an entirely new Modalpopup although I have tried using the same modal and it still doesn't work.
So the flow is:
User clicks button -> loading -> ModalPopup with tooltip -> User clicks 1 button out of 3 options -> Modalpopup closes -> loading -> ModalPopup number 2 with tooltip -> etc...
So it's loading dynamic content, then using delegation to set the tooltip listeners, then closing/deleting that content, then loading more dynamic content afterwards, and trying to again use delegated tooltip listeners for the second time.
I've tried removing the tooltip altogether on each modal load, unbinding everything on modal load before rebinding, unbinding in the tooltip code before rebinding, and etc.
Interestingly, when the second modalpopup opens, if I "Inspect Element" using chrome, the tooltips start working again.
Tootip Code:
(function ($) {
'use strict';
$.fn.extend({
jqToolTip: function () {
var opts = {
tooltipDiv: 'tooltipbox',
tooltipFadeOut: 'tooltipFadeOut',
tooltipBoxTop: 'tooltipbox-top',
tooltipBoxRight: 'tooltipbox-right',
tooltipBoxLeft: 'tooltipbox-left',
tooltipBoxBottom: 'tooltipbox-bottom',
tooltipBoxRed: 'tooltipbox-red',
tooltipBoxBottomRed: 'tooltipbox-bottom-red',
tooltipBoxTopRed: 'tooltipbox-top-red',
tooltipBoxLeftRed: 'tooltipbox-left-red',
tooltipBoxRightRed: 'tooltipbox-right-red'
};
const classSelector = $(this).attr("class").split(/\s+/).find(x => x.includes("tooltip"));
$(document.body).on('mouseenter', `.${classSelector}`, function (e) {
var color = $(this).data("tooltip-color");
var arrowOffsetx = $(this).data("tooltip-arrow-offset-x");
var arrowOffsety = $(this).data("tooltip-arrow-offset-y");
var helptext = $(this).data("tooltip");
var direction = $(this).data("tooltip-direction");
if (direction == null) direction = 'right';
var top = $(this).offset().top;
var left = $(this).offset().left;
var offsetX = $(this).data("tooltip-offset-x");
if (offsetX == null) offsetX = 0;
var offsetY = $(this).data("tooltip-offset-y");
if (offsetY == null) offsetY = 0;
//console.log(top,left,$(this).width());
var cssAdd = '';
var cssColorAdd = '';
$('..' + opts.tooltipDiv).removeClass(opts.tooltipFadeOut + ' '
+ opts.tooltipBoxBottom + ' '
+ opts.tooltipBoxRight + ' '
+ opts.tooltipBoxTop + ' '
+ opts.tooltipBoxLeft + ' '
+ opts.tooltipBoxRed + ' '
+ opts.tooltipBoxBottomRed + ' '
+ opts.tooltipBoxTopRed + ' '
+ opts.tooltipBoxLeftRed + ' '
+ opts.tooltipBoxRightRed).html(helptext);
switch (direction) {
case 'top': // top
top = top - 48 + offsetY;
left = left + $(this).width() / 2 - 25 + offsetX;
cssAdd = opts.tooltipBoxTop;
cssColorAdd = opts.tooltipBoxTopRed;
break;
case 'right': // right
top = top + $(this).height() / 2 - 13 + offsetY;
left = left + $(this).width() + 20 + offsetX;
cssAdd = opts.tooltipBoxRight;
cssColorAdd = opts.tooltipBoxRightRed;
break;
case 'bottom': // bottom
top = top + $(this). height() + 14 + offsetY;
left = left + $(this).width() / 2 - 28 + offsetX;
cssAdd = opts.tooltipBoxBottom;
cssColorAdd = opts.tooltipBoxBottomRed;
break;
case 'left': // left
top = top + $(this).height() / 2 - 13 + offsetY;
left = left - $('.' + opts.tooltipDiv).width() - 16 + offsetX;
cssAdd = opts.tooltipBoxLeft;
cssColorAdd = opts.tooltipBoxLeftRed;
break;
}
//console.log(left);
if (color == 'red') {
$('.' + opts.tooltipDiv).addClass(opts.tooltipBoxRed);
$('.' + opts.tooltipDiv).addClass(cssColorAdd);
}
if (typeof(arrowOffsetx) != "undefined" && arrowOffsetx.length > 0) {
$('.' + opts.tooltipDiv)
.addClass('tooltipBoxArrowOffsetX')
.append('<style>.tooltipBoxArrowOffsetX::after,.tooltipBoxArrowOffsetX::before{left:' + arrowOffsetx + ' !important;}</style>')
}
if (typeof (arrowOffsety) != "undefined" && arrowOffsety.length > 0) {
$('.' + opts.tooltipDiv)
.addClass('tooltipBoxArrowOffsetY')
.append('<style>.tooltipBoxArrowOffsetY::after,.tooltipBoxArrowOffsetY::before{left:' + arrowOffsety + ' !important;}</style>');
}
$('.' + opts.tooltipDiv).addClass(cssAdd).css({ left: left, top: top }).fadeIn();
})
$(document.body).on('mouseleave', `.${classSelector}`, function (e) {
$('.' + opts.tooltipDiv).addClass(opts.tooltipFadeOut);
})
$(document.body).on('click', `.${classSelector}`, function (e) {
var ishide = $(this).data("tooltip-onclickhide") == '1';
if (ishide) $('.' + opts.tooltipDiv).addClass(opts.tooltipFadeOut);
})
return this;
},
})
})(jQuery);
英文:
I have two ModalPopups
The first one opens and has a Tooltip text that the user can view for more detail with the "mouseenter" event listener.
Once the user clicks to close the modal through one of three buttons, the second ModalPopup opens with another Tooltip text. The Tooltip text on "mouseenter" does not work in this second ModalPopup.
This is an entirely new Modalpopup although I have tried using the same modal and it still doesn't work.
So the flow is:
User clicks button -> loading -> ModalPopup with tooltip -> User clicks 1 button out of 3 options -> Modalpopup closes -> loading -> ModalPopup number 2 with tooltip -> etc...
So it's loading dynamic content, then using delegation to set the tooltip listeners, then closing/deleting that content, then loading more dynamic content afterwards, and trying to again use delegated tooltip listeners for the second time.
I've tried removing the tooltip altogether on each modal load, unbinding everything on modal load before rebinding, unbinding in the tooltip code before rebinding, and etc.
Interestingly, when the second modalpopup opens, if I "Inspect Element" using chrome, the tooltips start working again.
Tootip Code:
(function ($) {
'use strict';
$.fn.extend({
jqToolTip: function () {
var opts = {
tooltipDiv: 'tooltipbox',
tooltipFadeOut: 'tooltipFadeOut',
tooltipBoxTop: 'tooltipbox-top',
tooltipBoxRight: 'tooltipbox-right',
tooltipBoxLeft: 'tooltipbox-left',
tooltipBoxBottom: 'tooltipbox-bottom',
tooltipBoxRed: 'tooltipbox-red',
tooltipBoxBottomRed: 'tooltipbox-bottom-red',
tooltipBoxTopRed: 'tooltipbox-top-red',
tooltipBoxLeftRed: 'tooltipbox-left-red',
tooltipBoxRightRed: 'tooltipbox-right-red'
};
const classSelector = $(this).attr("class").split(/\s+/).find(x => x.includes("tooltip"));
$(document.body).live('mouseenter', `.${classSelector}`, function (e) {
var color = $(this).data("tooltip-color");
var arrowOffsetx = $(this).data("tooltip-arrow-offset-x");
var arrowOffsety = $(this).data("tooltip-arrow-offset-y");
var helptext = $(this).data("tooltip");
var direction = $(this).data("tooltip-direction");
if (direction == null) direction = 'right';
var top = $(this).offset().top;
var left = $(this).offset().left;
var offsetX = $(this).data("tooltip-offset-x");
if (offsetX == null) offsetX = 0;
var offsetY = $(this).data("tooltip-offset-y");
if (offsetY == null) offsetY = 0;
//console.log(top,left,$(this).width());
var cssAdd = '';
var cssColorAdd = '';
$('.' + opts.tooltipDiv).removeClass(opts.tooltipFadeOut + ' '
+ opts.tooltipBoxBottom + ' '
+ opts.tooltipBoxRight + ' '
+ opts.tooltipBoxTop + ' '
+ opts.tooltipBoxLeft + ' '
+ opts.tooltipBoxRed + ' '
+ opts.tooltipBoxBottomRed + ' '
+ opts.tooltipBoxTopRed + ' '
+ opts.tooltipBoxLeftRed + ' '
+ opts.tooltipBoxRightRed).html(helptext);
switch (direction) {
case 'top': // top
top = top - 48 + offsetY;
left = left + $(this).width() / 2 - 25 + offsetX;
cssAdd = opts.tooltipBoxTop;
cssColorAdd = opts.tooltipBoxTopRed;
break;
case 'right': // right
top = top + $(this).height() / 2 - 13 + offsetY;
left = left + $(this).width() + 20 + offsetX;
cssAdd = opts.tooltipBoxRight;
cssColorAdd = opts.tooltipBoxRightRed;
break;
case 'bottom': // bottom
top = top + $(this).height() + 14 + offsetY;
left = left + $(this).width() / 2 - 28 + offsetX;
cssAdd = opts.tooltipBoxBottom;
cssColorAdd = opts.tooltipBoxBottomRed;
break;
case 'left': // left
top = top + $(this).height() / 2 - 13 + offsetY;
left = left - $('.' + opts.tooltipDiv).width() - 16 + offsetX;
cssAdd = opts.tooltipBoxLeft;
cssColorAdd = opts.tooltipBoxLeftRed;
break;
}
//console.log(left);
if (color == 'red') {
$('.' + opts.tooltipDiv).addClass(opts.tooltipBoxRed);
$('.' + opts.tooltipDiv).addClass(cssColorAdd);
}
if (typeof(arrowOffsetx) != "undefined" && arrowOffsetx.length > 0) {
$('.' + opts.tooltipDiv)
.addClass('tooltipBoxArrowOffsetX')
.append('<style>.tooltipBoxArrowOffsetX::after,.tooltipBoxArrowOffsetX::before{left:' + arrowOffsetx + ' !important;}</style>')
}
if (typeof (arrowOffsety) != "undefined" && arrowOffsety.length > 0) {
$('.' + opts.tooltipDiv)
.addClass('tooltipBoxArrowOffsetY')
.append('<style>.tooltipBoxArrowOffsetY::after,.tooltipBoxArrowOffsetY::before{left:' + arrowOffsety + ' !important;}</style>');
}
$('.' + opts.tooltipDiv).addClass(cssAdd).css({ left: left, top: top }).fadeIn();
})
$(document.body).live('mouseleave', `.${classSelector}`, function (e) {
$('.' + opts.tooltipDiv).addClass(opts.tooltipFadeOut);
})
$(document.body).live('click', `.${classSelector}`, function (e) {
var ishide = $(this).data("tooltip-onclickhide") == '1';
if (ishide) $('.' + opts.tooltipDiv).addClass(opts.tooltipFadeOut);
})
return this;
},
})
})(jQuery);
答案1
得分: 1
"mouseenter"和"mouseleave"事件的事件委托只能在捕获阶段执行。
用以下代码替换:
document.body.addEventListener('mouseenter', function(e) {
if (e.target.matches(`.${classSelector}`)) {
// 在这里编写代码
// 使用e.target代替this
}
}, true);
对于"mouseleave"事件也是相同的。
英文:
Event delegation for "mouseenter" and "mouseleave" events can only be done in the capturing phase.
Replace
$(document.body).live('mouseenter', `.${classSelector}`, function (e){}
with
document.body.addEventListener('mouseenter', function(e) {
if (e.target.matches(`.${classSelector}`)) {
// code here
// use e.target instead of this
}
}, true);
The same applies for "mouseleave".
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论