我试图制作一个可以多次添加到页面的确认控件,但是我偶然发现了导致这些控件彼此“接触”的错误(显然,我想让它们独立工作)。
我为此使用了Bootstrap,并且使用了尽可能少的jQuery(由于调试)。
经过切片后,我发现在我的代码中,Bootstrap关闭功能将运行多次,从而导致此问题。会有人知道为什么这个Bootstrap函数会多次运行吗?
这可能是我的问题的原因:
$("").on("hidden.bs.modal", function (e) {
//Why does this stack?
alert("Why does this stack?");
});
这是我代码的上下文,它将在其中多次运行:
//Yes selector
const positiveSelector = ".positive";
//No selector
const negativeSelector = ".negative";
//Confirm? selector
const confirmSelector = ".init-confirm"
//Pending selector
const pendingSelector = ".pending";
//Yes ele
const positiveNodes = document.querySelectorAll(positiveSelector);
//No ele
const negativeNodes = document.querySelectorAll(negativeSelector);
//Confirm? ele
const confirmNodes = document.querySelectorAll(confirmSelector);
//Pending ele
const pendingNodes = document.querySelectorAll(pendingSelector);
//Modal related:
const $modalInit = $(".modal").html();
const targetModal = $("#bs-modal-xl");
positiveNodes.forEach(node => node.addEventListener("click", function () {
let thisNode = this;
thisNode.classList.add("btn-success");
thisNode.parentNode.querySelectorAll(negativeSelector).forEach(node => node.classList.remove("btn-warning"));
thisNode.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.removeAttribute("disabled"));
}));
negativeNodes.forEach(node => node.addEventListener("click", function () {
let thisNode = this;
thisNode.classList.add("btn-warning");
thisNode.parentNode.querySelectorAll(positiveSelector).forEach(node => node.classList.remove("btn-success"));
thisNode.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.setAttribute("disabled", ""));
thisNode.parentNode.parentNode.querySelectorAll(pendingSelector).forEach(node => node.style.display = "none");
}));
confirmNodes.forEach(node => node.addEventListener("click", function () {
let thisNode = this;
thisNode.parentNode.querySelectorAll(pendingSelector).forEach(node => node.style.display = "inline-block");
thisNode.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-warning"));
thisNode.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-danger"));
thisNode.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Pending");
//Populate modal:
ModalHandler($(".my-ele").clone(), "My ele", undefined, true, true);
$(".modal .my-ele").show();
//Show Modal:
targetModal.modal();
$(".modal").on("click", ".my-ele button", function () {
targetModal.modal("hide");
});
//When closing Modal:
targetModal.on("hidden.bs.modal", function (e) {
//Why does this stack?
alert("Why does this stack?");
});
}));
//Modal handling (not required when not using Modal):
function ModalHandler(content, title, footer = "", bigCloseBtn = false, emptyFooter = false) {
$(".modal h4.modal-title").text(title);
$(".modal .modal-body").html(content);
if (footer != "" && footer != undefined) {
$(".modal .modal-footer").html(footer);
}
if (bigCloseBtn) {
$(".modal .modal-content .modal-header button.close").css("float", "right");
$(".modal .modal-content .modal-header button.close").addClass("btn btn-lg btn-danger");
//$(".modal .modal-content .modal-header button.close").html("close");
$(".modal .modal-content .modal-header button.close").removeClass("close");
}
if (emptyFooter) {
$(".modal .modal-content .modal-footer").html("");
}
}
$(".modal").on("hidden.bs.modal", function () {
$(".modal").html($modalInit);
});
#foo-container {
padding: 5px;
}
.pending {
display: none;
}
.my-ele {
display: none;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<div class="modal" id="bs-modal-xl" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p>One fine body…</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
<div id="foo-container">
<div class="confirmation-box">
<div class="btn-group btn-group-lg" role="group" aria-label="...">
<button type="button" class="btn btn-success positive">Yes</button>
<button type="button" class="btn btn-warning negative">No</button>
</div>
<button type="button" class="btn btn-lg btn-danger init-confirm" disabled>Confirm?</button>
<button type="button" class="btn btn-lg btn-danger pending" disabled>Pending</button>
</div>
<br />
<div class="confirmation-box">
<div class="btn-group btn-group-lg" role="group" aria-label="...">
<button type="button" class="btn btn-success positive">Yes</button>
<button type="button" class="btn btn-warning negative">No</button>
</div>
<button type="button" class="btn btn-lg btn-danger init-confirm" disabled>Confirm?</button>
<button type="button" class="btn btn-lg btn-danger pending" disabled>Pending</button>
</div>
</div>
<div class="my-ele">
<button type="button" class="btn btn-lg btn-success">Clicky</button>
</div>
为了重现我的问题,必须通过单击“是”按钮以启用“确认?”来打开模式。按钮,然后单击此按钮。然后退出模态。该事件将运行一次,但是,当重复打开和关闭模式时,警报将开始堆叠(由于事件由于某种原因而开始堆叠,我不理解)。
我有
的原因 .on("hidden.bs.modal", function (e) {});
在eventListener
<button type="button" class="btn btn-lg btn-danger init-confirm" disabled>Confirm?</button>
是因为我需要将clicked元素作为参数传递给外部函数。
我可以使模式关闭函数仅运行一次而不是“将它们堆叠”吗?
答案 0 :(得分:1)
这是因为该事件一次又一次地应用于targetModal.on
。您需要将其转到off
。
targetModal.off();
//Yes selector
const positiveSelector = ".positive";
//No selector
const negativeSelector = ".negative";
//Confirm? selector
const confirmSelector = ".init-confirm"
//Pending selector
const pendingSelector = ".pending";
//Yes ele
const positiveNodes = document.querySelectorAll(positiveSelector);
//No ele
const negativeNodes = document.querySelectorAll(negativeSelector);
//Confirm? ele
const confirmNodes = document.querySelectorAll(confirmSelector);
//Pending ele
const pendingNodes = document.querySelectorAll(pendingSelector);
//Modal related:
const $modalInit = $(".modal").html();
const targetModal = $("#bs-modal-xl");
positiveNodes.forEach(node => node.addEventListener("click", function() {
let thisNode = this;
thisNode.classList.add("btn-success");
thisNode.parentNode.querySelectorAll(negativeSelector).forEach(node => node.classList.remove("btn-warning"));
thisNode.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.removeAttribute("disabled"));
}));
negativeNodes.forEach(node => node.addEventListener("click", function() {
let thisNode = this;
thisNode.classList.add("btn-warning");
thisNode.parentNode.querySelectorAll(positiveSelector).forEach(node => node.classList.remove("btn-success"));
thisNode.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.setAttribute("disabled", ""));
thisNode.parentNode.parentNode.querySelectorAll(pendingSelector).forEach(node => node.style.display = "none");
}));
confirmNodes.forEach(node => node.addEventListener("click", function() {
let thisNode = this;
thisNode.parentNode.querySelectorAll(pendingSelector).forEach(node => node.style.display = "inline-block");
thisNode.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-warning"));
thisNode.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-danger"));
thisNode.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Pending");
//Populate modal:
ModalHandler($(".my-ele").clone(), "My ele", undefined, true, true);
$(".modal .my-ele").show();
//Show Modal:
targetModal.modal();
$(".modal").on("click", ".my-ele button", function() {
targetModal.modal("hide");
});
//When closing Modal:
targetModal.on("hidden.bs.modal", function(e) {
//Why does this stack?
alert("Why does this stack?");
targetModal.off();
});
}));
//Modal handling (not required when not using Modal):
function ModalHandler(content, title, footer = "", bigCloseBtn = false, emptyFooter = false) {
$(".modal h4.modal-title").text(title);
$(".modal .modal-body").html(content);
if (footer != "" && footer != undefined) {
$(".modal .modal-footer").html(footer);
}
if (bigCloseBtn) {
$(".modal .modal-content .modal-header button.close").css("float", "right");
$(".modal .modal-content .modal-header button.close").addClass("btn btn-lg btn-danger");
//$(".modal .modal-content .modal-header button.close").html("close");
$(".modal .modal-content .modal-header button.close").removeClass("close");
}
if (emptyFooter) {
$(".modal .modal-content .modal-footer").html("");
}
}
$(".modal").on("hidden.bs.modal", function() {
$(".modal").html($modalInit);
});
#foo-container {
padding: 5px;
}
.pending {
display: none;
}
.my-ele {
display: none;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<div class="modal" id="bs-modal-xl" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p>One fine body…</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
<div id="foo-container">
<div class="confirmation-box">
<div class="btn-group btn-group-lg" role="group" aria-label="...">
<button type="button" class="btn btn-success positive">Yes</button>
<button type="button" class="btn btn-warning negative">No</button>
</div>
<button type="button" class="btn btn-lg btn-danger init-confirm" disabled>Confirm?</button>
<button type="button" class="btn btn-lg btn-danger pending" disabled>Pending</button>
</div>
<br />
<div class="confirmation-box">
<div class="btn-group btn-group-lg" role="group" aria-label="...">
<button type="button" class="btn btn-success positive">Yes</button>
<button type="button" class="btn btn-warning negative">No</button>
</div>
<button type="button" class="btn btn-lg btn-danger init-confirm" disabled>Confirm?</button>
<button type="button" class="btn btn-lg btn-danger pending" disabled>Pending</button>
</div>
</div>
<div class="my-ele">
<button type="button" class="btn btn-lg btn-success">Clicky</button>
</div>