Knockout/JavaScript Ignore Multiclick

Knockout/JavaScript Ignore Multiclick

本文关键字:Multiclick Ignore JavaScript Knockout      更新时间:2023-09-26

我遇到一些用户多次点击按钮的问题,我想在第一个Ajax请求完成它的事情时抑制/忽略点击。例如,如果用户想要向他们的购物车中添加商品,他们点击添加按钮。如果他们多次点击添加按钮,它就会抛出一个PK违规,因为它试图将重复的商品插入购物车。

所以这里提到了一些可能的解决方案:使用knockout.js防止双击按钮这里:如何防止使用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调用完成之前不够快地更新按钮的可见绑定,或者每次单击按钮时都会创建一个新的criticalSectionInd实例,而不是真正充当全局变量。

如果我做错了,我会使用其他帖子中提到的方法,只是这种方法似乎更容易实现,而不必重构我所有的按钮来使用jQuery One()功能。

您应该在回调方法中设置app.ajaxService.criticalSection(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中使用"disable"绑定来防止触发锚标记的click绑定。

是一个小片段。只需在操作开始时将标志设置为true,并在执行完成时再次将其设置为false。同时,disable绑定会阻止用户执行click功能。

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>