【发布时间】:2019-10-08 22:41:41
【问题描述】:
目前,我正在尝试通过打开 Bootstrap 模态以及将这些相同的模态用于不同的功能来使用户能够确认某些内容。在这个问题中,我将使用“计算器”类型的元素作为附加功能的示例。就目前而言,除非我将 JQuery 的 $target.off(); 添加到 targetModal.on("hidden.bs.modal", function (e) {});,否则确认将不起作用。
当我添加这段 JQuery 代码时,它会导致我在此页面上使用的任何其他功能(关于 Bootstrap 模态)也中断,这意味着我需要为任何这些功能添加额外的代码。我不希望这种情况发生。如何在不为这些功能添加额外代码的情况下使这些确认正常工作,同时保持其他功能正常工作?
应该发生什么:
- 选择“否”时,按钮(用于“No”显然)应保持相同的颜色,但相反的按钮(“是”按钮)应转动灰色和“确认?”按钮应该被禁用(如果还没有)。此外,如果
<button class="btn btn-warning pending">Pending</button>可见,则应将其隐藏。 - 选择“是”时,按钮(对于“是”)应保持相同的颜色,但相反的按钮(“否”按钮)应该变灰,“确认?”按钮应启用。
- 什么时候“确认?”单击按钮时,它应该使用与确认相关的任何内容填充模态并打开给定的模态。
- 当模式退出/关闭在确认没有完成确认时,函数
WillClose()(这反过来应该改变给定的待定按钮文本应执行“重试”的确认控制)。 - 成功执行确认后(通过单击给定模式中的“确认”按钮),模式应隐藏/消失(并重置内部内容)并执行
ConfirmModal()功能(这反过来应该禁用所有按钮对于给定的确认控件并将待定按钮文本更改为“已确认”)。 - 这些确认中的任何一个都应该彼此独立工作。
发生了什么:
除非我将$target.off() 添加到模态框(例如targetModal.off()),否则确认元素会触发彼此的待处理按钮。但是,执行后者会导致其他功能“中断”。我的意思是,无论将在模态中“填充”、“插入”或“克隆”(无论你想怎么称呼它),它都会被多次放置在模态中(好像模态没有重置,有意义吗?)。
我怎样才能完成以下工作?
//Fields:
//Yes selector
const positiveSelector = ".positive";
//No selector
const negativeSelector = ".negative";
//Confirm? selector
const confirmSelector = ".init-confirm";
//Pending selector
const pendingSelector = ".pending";
//calTrigger selector
const calcTriggerSelector = ".calc-trigger > button";
//Yes elements
const positiveNodes = document.querySelectorAll(positiveSelector);
//No elements
const negativeNodes = document.querySelectorAll(negativeSelector);
//Confirm? elements
const confirmNodes = document.querySelectorAll(confirmSelector);
//Pending elements
const pendingNodes = document.querySelectorAll(pendingSelector);
//calcTrigger elements
const calcTriggerNodes = document.querySelectorAll(calcTriggerSelector);
//Modal
const targetModalSelector = "#bs-modal-xl";
const targetModal = $(targetModalSelector);
const $modalInit = targetModal.html();
//Eventlisteners:
positiveNodes.forEach(node => node.addEventListener("click", function () {
EnableConfirmBtn(this);
}));
negativeNodes.forEach(node => node.addEventListener("click", function () {
DisableConfirmBtn(this);
}));
confirmNodes.forEach(node => node.addEventListener("click", function () {
OpenConfirmModal(this);
}));
calcTriggerNodes.forEach(node => node.addEventListener("click", calcTrigger));
//Reset modal when closing
targetModal.on("hidden.bs.modal", function () {
targetModal.html($modalInit);
});
//Methods:
function EnableConfirmBtn(ele) {
ele.classList.add("btn-success");
ele.parentNode.querySelectorAll(negativeSelector).forEach(node => node.classList.remove("btn-warning"));
ele.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.removeAttribute("disabled"));
}
function DisableConfirmBtn(ele) {
ele.classList.add("btn-warning");
ele.parentNode.querySelectorAll(positiveSelector).forEach(node => node.classList.remove("btn-success"));
ele.parentNode.parentNode.querySelectorAll(confirmSelector).forEach(node => node.setAttribute("disabled", ""));
}
function OpenConfirmModal(ele) {
ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.style.display = "inline-block");
ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-warning"));
ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-danger"));
ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Pending");
$(targetModalSelector + " .modal-body").html($(".clone-one").clone());
$(targetModalSelector + " .clone-one").show();
$(targetModalSelector + " h4.modal-title").text("");
$(targetModalSelector + " .modal-content .modal-footer").html("");
targetModal.modal();
targetModal.on("click", ".clone-one", function () {
targetModal.modal("hide");
ConfirmModal(ele);
});
targetModal.on("hidden.bs.modal", function (e) {
WillClose(ele);
//Make use of targetModal.off(); here? <--
//targetModal.off();
targetModal.html($modalInit);
});
}
function ConfirmModal(ele) {
ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Confirmed");
ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-danger", "btn-warning"));
ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-success"));
ele.parentNode.querySelectorAll(confirmSelector).forEach(node => node.style.display = "none");
ele.parentNode.querySelectorAll(".btn-group > button").forEach(node => node.setAttribute("disabled", ""));
}
function WillClose(ele) {
ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.textContent = "Try again");
ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.remove("btn-danger"));
ele.parentNode.querySelectorAll(pendingSelector).forEach(node => node.classList.add("btn-warning"));
}
function calcTrigger() {
ModalHandler($(".calc").clone(), "", "", true, true);
$(targetModalSelector + " .calc").show();
targetModal.modal();
document.querySelectorAll(targetModalSelector + " .calc #number-one-btn").forEach(node => node.addEventListener("click", function () {
document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "1");
}));
document.querySelectorAll(targetModalSelector + " .calc #number-two-btn").forEach(node => node.addEventListener("click", function () {
document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "2");
}));
document.querySelectorAll(targetModalSelector + " .calc #number-three-btn").forEach(node => node.addEventListener("click", function () {
document.querySelectorAll(targetModalSelector + " .calc .result-container input").forEach(node => node.value += "3");
}));
//I would not want to be using something like this:
//Reset modal when closing
//targetModal.on("hidden.bs.modal", function () {
//targetModal.off();
//targetModal.html($modalInit);
//});
}
//Modal handling (not required when not using Modal):
function ModalHandler(content, title, footer = "", bigCloseBtn = false, emptyFooter = false) {
$(targetModalSelector + " h4.modal-title").text(title);
$(targetModalSelector + " .modal-body").html(content);
if (footer != "" && footer != undefined) {
$(targetModalSelector + " .modal-footer").html(footer);
}
if (bigCloseBtn) {
$(targetModalSelector + " .modal-content .modal-header button.close").css("float", "right");
$(targetModalSelector + " .modal-content .modal-header button.close").addClass("btn btn-lg btn-danger");
//$(".modal .modal-content .modal-header button.close").html("close");
$(targetModalSelector + " .modal-content .modal-header button.close").removeClass("close");
}
if (emptyFooter) {
$(targetModalSelector + " .modal-content .modal-footer").html("");
}
}
#foo-container {
padding: 5px;
}
.pending {
display: none;
}
.clone-one, .calc {
display: none;
}
.calc {
width: 100%;
}
.calc button, .calc .result-container {
margin-top: 3px;
margin-bottom: 3px;
}
.calc [class*="col-"] {
padding-left: 3px;
padding-right: 3px;
}
<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="calc" class="calc">
<form>
<div class="row">
<div class="col-xs-9">
<div class="result-container">
<input type="text" class="form-control" disabled>
</div>
</div>
<div class="col-xs-3">
<button type="button" class="btn btn-default btn-block" value="x" id="">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
</div>
<div class="row">
<div class="col-xs-3">
<button type="button" class="btn btn-default btn-block" value="1" id="number-one-btn">
1
</button>
</div>
<div class="col-xs-3">
<button type="button" class="btn btn-default btn-block" value="2" id="number-two-btn">
2
</button>
</div>
<div class="col-xs-3">
<button type="button" class="btn btn-default btn-block" value="3" id="number-three-btn">
3
</button>
</div>
<div class="col-xs-3">
<button type="button" class="btn btn-default btn-block" value="" id="number-one-btn">
<span class="glyphicon glyphicon-arrow-left"></span>
</button>
</div>
</div>
</form>
</div>
<div class="container">
<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>
<br />
<div class="calc-trigger">
<button class="btn btn-lg btn-default">
Calc trigger
</button>
</div>
</div>
<div class="clone-one">
<button type="button" class="btn btn-lg btn-success">Clicky</button>
</div>
</div>
我只是在寻找一种需要尽可能少的代码的解决方案。如果给定的示例可以重写为更小,请告诉我。
编辑:我知道上面提供的代码添加了多个事件侦听器,我单击某些导致问题的控件的次数越多。这就是为什么我正在寻找一种(尽可能简单的)解决方案,以使所有这些控件独立工作,同时保持脚本不引人注目,并尽可能多地保留上面提供的代码格式。
【问题讨论】:
标签: javascript jquery html