javascript - knockout/JavaScript 忽略多重点击

标签 javascript jquery knockout.js asp.net-mvc-5

用户多次单击按钮时遇到一些问题,我想在第一个 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/

相关文章:

knockout.js - 渲染后 knockout ,但只有一次

javascript - 滚动子 div 滚动窗口,我该如何停止?

javascript - 尝试限制 div 移动时出现问题

javascript - 单击禁用的 <select> 选项框时如何触发警报消息?

javascript - 如何在 setTimeout 函数回调后增加计数器变量?

javascript - 如何使用 CSS 或 jQuery 完全重置 div CSS

knockout.js - 将 knockoutjs 对象移动到弹出编辑表单中

javascript - 在 JavaScript 中制作全局变量的本地副本

javascript - 断开 sails.js socket.io 的逻辑

knockout.js - 在 knockoutjs 中使用选中的绑定(bind)时防止事件冒泡