用户多次单击按钮时遇到一些问题,我想在第一个 Ajax 请求执行其操作时抑制/忽略单击。例如,如果用户想要将商品添加到购物车,他们可以单击“添加”按钮。如果他们多次单击“添加”按钮,则会引发 PK 违规,因为它试图将重复的商品插入购物车。
所以这里提到了一些可能的解决方案:Prevent a double click on a button with knockout.js 在这里:How to prevent a double-click using jQuery?
但是,我想知道下面的方法是否是另一种可能的解决方案。目前,我使用覆盖整个屏幕的透明“保存”div 来尝试防止点击,但仍然有些人设法双击。我假设是因为他们点击的速度比 div 渲染的速度快。为了解决这个问题,我尝试使用全局变量来锁定 Ajax 调用。
按钮
<a href="#" class="disabled btn btn-default" data-bind="click: $root.AddItemToCart, visible: InCart() == false"><span style="SomeStyles">Add</span></a>
Knockout 在单击按钮时执行此脚本
vmProductsIndex.AddItemToCart = function (item) {
if (!app.ajaxService.inCriticalSection()) {
app.ajaxService.criticalSection(true);
app.ajaxService.ajaxPostJson("@Url.Action("AddItemToCart", "Products")",
ko.mapping.toJSON(item),
function (result) {
ko.mapping.fromJS(result, vmProductsIndex.CartSummary);
item.InCart(true);
item.QuantityOriginal(item.Quantity());
},
function (result) {
$("#error-modal").modal();
},
vmProductsIndex.ModalErrors);
app.ajaxService.criticalSection(false);
}
}
调用此脚本
(function (app) {
"use strict";
var criticalSectionInd = false;
app.ajaxService = (function () {
var ajaxPostJson = function (method, jsonIn, callback, errorCallback, errorArray) {
//Add the item to the cart
}
};
var inCriticalSection = function () {
if (criticalSectionInd)
return true;
else
return false;
};
var criticalSection = function (flag) {
criticalSectionInd = flag;
};
// returns the app.ajaxService object with these functions defined
return {
ajaxPostJson: ajaxPostJson,
ajaxGetJson: ajaxGetJson,
setAntiForgeryTokenData: setAntiForgeryTokenData,
inCriticalSection: inCriticalSection,
criticalSection: criticalSection
};
})();
}(app));
问题仍然是我可以垃圾邮件单击按钮并获得主键违规。我不知道这种方法是否有缺陷,并且 Knockout 不够快,无法在第一个 Ajax 调用完成之前更新按钮的可见绑定(bind),或者每次单击按钮时都会创建一个新的 CriticalSectionInd 实例,但没有真正起作用作为全局变量。
如果我的做法是错误的,我将使用其他帖子中提到的方法,只是这种方法似乎更容易实现,而无需重构所有按钮来使用 jQuery One() 功能。
最佳答案
您应该在回调方法中设置app.ajaxService.riticSection(false);
。
现在您正在 if 子句末尾执行这行代码,而不是在成功或错误回调内部执行,因此它会在 ajax 调用完成之前执行。
vmProductsIndex.AddItemToCart = function (item) {
if (!app.ajaxService.inCriticalSection()) {
app.ajaxService.criticalSection(true);
app.ajaxService.ajaxPostJson("@Url.Action("AddItemToCart", "Products")",
ko.mapping.toJSON(item),
function (result) {
ko.mapping.fromJS(result, vmProductsIndex.CartSummary);
item.InCart(true);
item.QuantityOriginal(item.Quantity());
app.ajaxService.criticalSection(false);
},
function (result) {
$("#error-modal").modal();
app.ajaxService.criticalSection(false);
},
vmProductsIndex.ModalErrors);
}
}
您可以使用 knockout 中的“禁用”绑定(bind)来防止触发 anchor 标记的点击绑定(bind)。
这里有一个小片段。只需在操作开始时将标志设置为 true,并在执行完成时再次将其设置为 false。同时,禁用绑定(bind)会阻止用户执行点击功能。
function viewModel(){
var self = this;
self.disableAnchor = ko.observable(false);
self.randomList = ko.observableArray();
self.loading = ko.observable(false);
self.doWork = function(){
if(self.loading()) return;
self.loading(true);
setTimeout(function(){
self.randomList.push("Item " + (self.randomList().length + 1));
self.loading(false);
}, 1000);
}
}
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<a href="#" data-bind="disable: disableAnchor, click: doWork">Click me</a>
<br />
<div data-bind="visible: loading">...Loading...</div>
<br />
<div data-bind="foreach: randomList">
<div data-bind="text: $data"></div>
</div>
关于javascript - knockout/JavaScript 忽略多重点击,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33128159/