Knockout JS 购物车练习

Posted

技术标签:

【中文标题】Knockout JS 购物车练习【英文标题】:Knockout JS shopping cart exercise 【发布时间】:2017-03-30 13:48:58 【问题描述】:

我正在学习淘汰赛 js,并已经开始构建一个简单的购物车。

这个购物车基本上要求用户从下拉列表中选择一个类别,然后在第二个下拉列表中填充产品。

当用户选择产品时,会显示产品信息,即名称/价格/数量/总数。 “添加项目”按钮也是可见的。

数量数据是一本教科书,用户可以在其中增加值。如果用户增加数量值,总值将计算新的总值,即(价格 * 数量)。

当用户单击添加项目按钮时,产品 ID、名称、数量和总数将存储并显示(ID 除外)在相邻的 div 即购物车列表中。

我遇到的问题是,当购物车中的商品数量为 1 时,我想向购物车中添加数量为 2 的新商品。购物车中的数量值也变为 2。值应保持为 1,购物车中的总值与新商品的总值相匹配。

代码如下:

<div id="exp2">
    <div>
        <span>
            <select id="ddlCat" data-bind="options: lstCategories, optionsText: 'name',
            optionsValue: 'id', optionsCaption: 'Select Category...',
            value: selectedCate"></select>
        </span>
        <span data-bind="visible: lstProducts().length > 0">
            <select id="ddlProd" data-bind="options: lstProducts, optionsText: 'name',
            optionsValue: 'id',  optionsCaption: 'Select Product...',
            value: selectedProdId"></select>
        </span>
        <span data-bind="with: selectedProd()">
            Price: £<span id="pPrice" data-bind="text: price"></span>, &nbsp;
            Qty <input type="text" id="pQty" data-bind="value: quantity" style="width:30px;"
                       placeholder="" required />
            SubTotal: £<span data-bind="text: itemTotal()"></span>
            <span><button id="btnAdd" class="btnAdd" data-bind="click: addItem">Add to cart</button></span>
        </span>
    </div>
    <div>
        <h3>Items In Cart</h3>
        <ul id="lstCart" data-bind="foreach: cart">
            <li>
                Name: <span data-bind="text: name"></span>&nbsp;
                Qty: <span data-bind="text: qty"></span>&nbsp;
                Item Total: £<span data-bind="text: itemTotal"></span>&nbsp;
            </li>
        </ul>
        Sub Total: £<span data-bind="text: subTotal()"></span>
    </div>
  </div>

javascript

        var categories = [];
        var products = [];
        var cartLines = [];

        $.ajax(
            url: '../KnockoutTut/page5GetCat',
            type: "GET", cache: false, async: false,
            contentType: "application/json; charset=utf-8",
            dataType: "json", traditional: true,
            success: function (data) 
                //alert('Process Successful');
                for (var i = 0; i < data.length; i++) 
                    var id = data[i].id; var name = data[i].name;
                    //var nCat = new Category(id, name);
                    categories.push( new Category(id,name));
                
            ,
            error: function (jqXHR, textStatus, errorThrown) 
                //alert("Error")
                alert(jqXHR.status + "," + jqXHR.responseText + "," + errorThrown);
            
        );

        function getProd(catId) 
            products = [];
            var value =  'value': catId ;
            var json = JSON.stringify(value);
            $.ajax(
                url: '../KnockoutTut/page5GetProd',
                type: "POST", data: json, cache: false, async: false,
                contentType: "application/json; charset=utf-8",
                dataType: "json", traditional: true,
                success: function (data) 
                    //alert('Process Successful');
                    for (var i = 0; i < data.length; i++) 
                        var id = data[i].id; var name = data[i].name;
                        var price = data[i].price; var qty = data[i].qty;
                        products.push(new Product(id, name, price, 1));
                    
                ,
                error: function (jqXHR, textStatus, errorThrown) 
                    //alert("Error")
                    alert(jqXHR.status + "," + jqXHR.responseText + "," + errorThrown);
                
            );
        

        function Category(id, name) 
            this.id = id;
            this.name = name;
        ;

        function Item(id, name, qty, itemTotal) 
            this.id = id;
            this.name = name;
            this.qty = qty;
            this.itemTotal = itemTotal;
        ;

        function Product(id, name, price, qty) 
            this.id = id;
            this.name = name;
            this.price = price;
            this.qty = qty;
        ;

        function viewModel() 

            var self = this;
            self.lstCategories = ko.observableArray(categories);
            self.lstProducts = ko.observableArray([]);
            self.cart = ko.observableArray([]);
            self.selectedCate = ko.observable();
            self.selectedProdId = ko.observable();
            self.selectedProd = ko.observable();
            self.quantity = ko.observable(1);
            self.catQty = ko.observable();

            self.itemTotal = ko.pureComputed(function () 
                return self.selectedProd() ? self.selectedProd().price * parseInt("0" + self.quantity(), 10) : 0;
            );

            self.subTotal = ko.pureComputed(function () 
                var total = 0;
                $.each(self.cart(), function ()  total += this.itemTotal() )
                return total;
            );

            self.selectedCate.subscribe(function (pCatId) 
                var catId = pCatId;
                if ($.isNumeric(catId)) 
                    getProd(catId);
                
                self.lstProducts(products);
            );

            self.selectedProdId.subscribe(function (pProdId) 
                var pId = pProdId;
                var match = ko.utils.arrayFirst(lstProducts(), function (item) 
                    return pId === item.id;
                );
                self.selectedProd(match);
                //alert(selectedProd().qty);
            );

            self.addItem = function (item) 
                var nId = item.id; var nName = item.name; var cartQty = quantity; var iTot = itemTotal;
                cart.push(new Item(nId, nName, cartQty, iTot));
                //cart.push(cartLines);
            ;                
        ;
        ko.applyBindings(viewModel, document.getElementById("exp2"));

请记住,我是淘汰 js 的新手。所以请原谅糟糕的编码。谢谢

【问题讨论】:

【参考方案1】:

问题似乎在于您在添加项目后使用什么值来显示数据。如果我没记错的话,您将 observable 分配给 cart 数组内的属性 cartQty。因为,您在cart 中使用添加的值只是为了显示为标签信息,并且用户不应该更改它(当然,除非在删除该记录然后在所需修改后添加新记录之后),所以没有必要使用双向绑定,因此无需像您在这里所做的那样分配 observable -

var cartQty = quantity;

因此,通过仅分配可观察对象所包含的值而不是可观察对象本身来将它们分开总是更好。

你可以试试这样的 -

var cartQty = quantity();

所以改变数量不会在其他地方产生副作用。

【讨论】:

谢谢,您的建议奏效了。我将购物车数量 = 数量更改为购物车数量 = 数量()。为了让我更好地理解。如果我执行 var a = b ( b 是可观察的)之类的赋值,a 基本上是 b 的副本,即 a 现在也是可观察的。而如果我做了 a = b(),a 引用了 b 中包含的值。 宾果游戏!你明白了:)请接受这个作为答案,以便将来对其他人有所帮助..

以上是关于Knockout JS 购物车练习的主要内容,如果未能解决你的问题,请参考以下文章

angularjs购物车练习

python练习_购物车(简版)

vue 购物车练习

购物车练习

Python 练习1——简易购物车

购物车程序练习