关闭

knockout.js实例二~购物车

标签: knockoutjs
979人阅读 评论(0) 收藏 举报
分类:

knockout.js实例二~购物车

本实例完成了一个基本的购物车功能,涉及到knockout.js中的知识点包含 select 标签的绑定, select 标签的级联, with 绑定,数据格式化, 依赖属性以及模板绑定等, 先上代码:

ViewModel Code:

var categories = [
    {
        Name: '服饰',
        Products:[
            {Name: '七分裤', Price:49.9},
            {Name: '休闲裤', Price:59.9},
            {Name: '卫衣', Price:69.9}
        ]
    },
    {
        Name: '生活用品',
        Products: [
            {Name: '海飞丝', Price:9.9},
            {Name: '霸王', Price:19.9},
            {Name: '潘婷', Price:29.9}
        ]
    },
    {
        Name: '饮料',
        Products: [
            {Name: '百事可乐', Price:3.9},
            {Name: '脉动', Price:4.9},
            {Name: '乐虎', Price:5.9}
        ]
    }
];

function cartModel(){
    var self = this;
    self.category = ko.observable();
    self.product = ko.observable();
    self.quantity = ko.observable(1);
    self.subtotal = ko.computed(
        function () {
            return self.product() ? self.product().Price * self.quantity() : 0;
        },
        self
    );
}


function cartsViewModel(){
    var self = this;

    self.categories = ko.observableArray(categories);

    self.carts = ko.observableArray([new cartModel()]);

    self.addProduct = function () {
        self.carts.push(new cartModel());
    };

    self.removeProduct = function (product) {
        self.carts.remove(product);
    };


    self.totalPrice = ko.computed(
        function () {
            var total = 0;

            $.each(self.carts(),
                function (index, item) {
                    total += item.subtotal();
                }
            );

            return total;
        },
        self
    );

    self.commitCart = function () {
        var dataToSave = $.map(self.carts(),
            function(cart) {
            return cart.product() ? {
                product: cart.product().Name,
                quantity: cart.quantity()
            }: undefined
        });
        alert(ko.toJSON(dataToSave));
    };

    self.moneyFormat = function (value){
        return '$' + value.toFixed(2);
    };


}

ko.applyBindings(new cartsViewModel());

Html Code:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Carts Editor</title>
    <link rel="stylesheet" href="../css/bootstrap.min.css"/>
</head>
<body>

    <script type="text/html" id="cartsTemplate">
        <tr>
            <td>
                <select class="form-control" data-bind="options: categories, optionsText: 'Name', optionsCaption:'选择类别...', value: category"></select>
            </td>
            <td data-bind="with: category">
                <select class="form-control" data-bind="options: Products, optionsText: 'Name', optionsCaption:'选择商品...',  value: $parent.product"></select>
            </td>
            <td>
                <span data-bind="visible: product, text: $parent.moneyFormat(product() ? product().Price : 0)"></span>
            </td>
            <td>
                <input class="form-control" type="text" data-bind="visible: product, value: quantity, valueUpdate: 'afterkeydown'"/>
            </td>
            <td>
                <span data-bind="visible: product, text: $parent.moneyFormat(subtotal())"></span>
            </td>
            <td>
                <a href="#" class="btn btn-danger btn-sm" data-bind="click: $parent.removeProduct">移除</a>
            </td>
        </tr>
    </script>
    <hr/>

    <div class="container">
        <div class="row">
            <a href="#" class="btn btn-primary btn-sm" data-bind="click: addProduct">新增</a>&nbsp;
            <a href="#" class="btn btn-primary btn-sm" data-bind="click: commitCart">提交</a>
            <span class="col-md-2 pull-right" data-bind="text: '总计:' + moneyFormat(totalPrice())"></span>
            <table class="table table-hover table-bordered table-responsive">
                <thead>
                    <tr>
                        <th class="col-md-2">类别</th>
                        <th class="col-md-2">名称</th>
                        <th class="col-md-2">单价</th>
                        <th class="col-md-2">数量</th>
                        <th class="col-md-2">小计</th>
                        <th class="col-md-2">操作</th>
                    </tr>
                </thead>
                <tbody data-bind="template:{name: 'cartsTemplate', foreach: carts}">
                </tbody>
            </table>
        </div>
    </div>

    <script type="text/javascript" src="../scripts/jquery-1.9.1.min.js"></script>
    <script type="text/javascript" src="../scripts/knockout-3.3.0.js"></script>
    <script type="text/javascript" src="../viewModels/cartsViewModel.js"></script>
</body>
</html>

首先我在ViewModel中为了模拟数据, 使用了静态的 categories 来作为基本数据, 它的结构很清晰, Name 表示类型名称,
Products 表示与类型所对应的商品, 以及里面的 Name 表示商品名称, Price 表示商品单价。 接下来我们需要构建一个cartModel 来表示我们单个选择好的商品, 它需要具备以下几个属性: 商品类别, 商品(包含名称与价格),数量, 小计价格。 注意在此小计价格是由商品单价以及数量所计算出来的, 所以小计价格是依赖于商品与数量的,所以他是一个依赖属性, 对于依赖属性, 我们使用ko.computed来声明 ko.computed 的签名为 ko.computed(func, target), func 是一个返回此小计属性的值得函数, 在javascript中, 函数并不属于某个具体的对象, 只是在调用的时候被某个对象所调用, 也就是来设定其作用域, target 即表示需要将此函数的作用域设置为 target的值。

下面我们继续构建一个cartsViewModel 作为我们需要绑定到 html 页面的 viewmodel, 在这个模型中,我们首先需要将商品类型作为我们绑定商品类型 select 的数据源 ,即

self.categories = ko.observableArray(categories); 

接着我们需要定义一个 cartModel 的数组用于绑定我们页面上的购物车列表, 即

self.carts = ko.observableArray([new cartModel()]); 

还有对于商品的增加和移除,分别为:

self.addProduct = function () {
    self.carts.push(new cartModel());
};

self.removeProduct = function (product) {
    self.carts.remove(product);
};

对于商品的新增,我们只需要往 self.carts对象中push一个空的 cartModel就行, 对于移除,只需将传入的product 从 self.carts中移除就行, 因为我们的 self.carts 是一个监控对象, 且绑定了 html 页面的购物车列表模板, 所以当我们的 self.carts 产生变化的时候, ui界面也会产生相对应的变化。

下面我们需要计算所选上面总价,以及向我们的远程服务器提交我们的数据:

self.totalPrice = ko.computed(
    function () {
        var total = 0;
        $.each(self.carts(),
            function (index, item) {
                total += item.subtotal();
            }
        );
        return total;
    },
    self
);

self.commitCart = function () {
    var dataToSave = $.map(self.carts(),
        function(cart) {
        return cart.product() ? {
            product: cart.product().Name,
            quantity: cart.quantity()
        }: undefined
    });
    alert(ko.toJSON(dataToSave));
};

首先我们看 self.totalPrice , 此函数遍历了我们的 self.carts , 然后将每一项产品的小计价格进行相加, 得到总价, 较为好理解。 self.commitCart 函数对我们的 self.carts 进行映射, 获取每一项商品的名称与所选数量, 映射到一个新的 数组中, 然后同我们 ko.toJSON 函数来讲这个数组转化为Json数据。

注意一点就是: 在上面的映射过程中,我们是取到了商品的名称, 但是实际开发过程中, 由于我们需要获取与标识符所对应的唯一商品, 所以一般我们会在初始化数据中加入可以标示商品唯一的Id, 然后在映射新的数组已用来提交时会映射出这个唯一的标志Id。

对于单价,小计,总计,我们需要对其进行格式化处理:

self.moneyFormat = function (value){
    return '$' + value.toFixed(2);
};

toFixed 函数保证了其保留两位小数, 前面的美元符号依情况而定。

下面不要忘记我们最重要的一部操作,应用绑定:

ko.applyBindings(new cartsViewModel());

好,下面我们接着来看html code :

首先我们看上面用到的购物车模板:

<script type="text/html" id="cartsTemplate">
    <tr>
        <td>
            <select class="form-control" data-bind="options: categories, optionsText: 'Name', optionsCaption:'选择类别...', value: category"></select>
        </td>
        <td data-bind="with: category">
            <select class="form-control" data-bind="options: Products, optionsText: 'Name', optionsCaption:'选择商品...',  value: $parent.product"></select>
        </td>
        <td>
            <span data-bind="visible: product, text: $parent.moneyFormat(product() ? product().Price : 0)"></span>
        </td>
        <td>
            <input class="form-control" type="text" data-bind="visible: product, value: quantity, valueUpdate: 'afterkeydown'"/>
        </td>
        <td>
            <span data-bind="visible: product, text: $parent.moneyFormat(subtotal())"></span>
        </td>
        <td>
            <a href="#" class="btn btn-danger btn-sm" data-bind="click: $parent.removeProduct">移除</a>
        </td>
    </tr>
</script>
  • 商品类别:

options: 绑定了我们需要展示的类别数据源, 即 self.categories

optionsText: 绑定了类别的显示字段, 如果有需要的话, 会使用 optionsValue 来绑定值字段

optionsCaption: 绑定了类别的初始化显示提示

value: 绑定了所选类别的值

  • 商品:

注意一下, 我们在这里使用了 with 绑定, 这个绑定表示可以在此所属标签的下级标签中访问绑定值的子属性字段, 由于我们需要选择的商品初始化数据包含在 categories 中, 所以当我们选择了某一个 category 之后, 我们可以通过它的子属性 Products 来访问与此类型关联的商品数据, 所以我们可以看到在这里我们的 options 绑定的是Products, 后续两项我就不做介绍了, 跳过看 value 绑定, value 绑定了我们单个购物车项的 product, 注意我们这里的 parent,使parent 呢? 是因为当前作用域是在 with: category 中的, 如果我们需要访问 product, 则需要往上一次进行查找。

  • 单价:

绑定了 cartModel 里面的所选商品对象 product 的子属性 Price, 所以值为 product().Price

  • 数量:

绑定了 cartModel 里面的所选商品数量 quantity, 设置 valueUpdate: ‘afterkeydown’ 是为了在用户按下键之后立刻更新商品数量数据

  • 小计:

绑定了 cartModel 里面的所选商品数量 subtotal

注意:在我们的单价, 数量, 小计中,我们绑定了 visible: product, 这是为了当 product 没有选择的情况下,是不需要用户看到的。

模板定义好了,下面就需要对模板的绑定:

<tbody data-bind="template:{name: 'cartsTemplate', foreach: carts}">
</tbody>

剩下的就是对新增,提交,以及总价的绑定了,较为简单,具有 knockout.js基本知识的就可以理解了。

0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

用Vue的一个购物车(1),虽然是自己写的但是也是来源于脚本之家的案例,就算转载啦

百度的时候看别人的代码总是,这几天没有事情,这几天项目需要,随便研究了一下巴拉巴拉巴拉,写了一个demo,大家看看,结果,看不懂,果然是太笨了,我是纯菜鸟啊!!!!TOT,然后我也不知道怎么才能把这个...
  • realDE
  • realDE
  • 2016-11-28 08:55
  • 3240

Vue2.0实现购物车示例

简介vue.js是由华人尤雨溪开发的一套MVVM框架。vue.js 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统,它非常适用于交互处理非常多(如表单操作),而且页面中的内...
  • ParanoidYang
  • ParanoidYang
  • 2017-06-05 11:29
  • 3250

Vue2.0开发购物车实例

前言 虽然Vue最强大的是组件化开发,但是其实多页面开发也蛮适合的。看了慕课网的使用Vue2.0开发购物车的教程之后,自己也实现了一遍。http://www.imooc.com/article/16...
  • Lucky_LXG
  • Lucky_LXG
  • 2017-03-31 08:40
  • 2339

【实例】仿购物车原理-高级Action应用二(通过DispatchAction方式)

本篇文章是对上一篇文章"【实例】仿购物车原理-高级Action应用一(普通传参方式)"功能进行完善。 通过DispatchAction类把删除和添加购物车的方法,归纳到一个Action里面。 1.使用...
  • ribmusic
  • ribmusic
  • 2015-02-13 09:55
  • 308

asp.net中购物车的两种存储方式Session和Cookie的应用实例

asp.net中购物车的两种存储方式Session和Cookie的应用实例 收藏 1.这是用Cookie存储的购物车的几种常用的操作:   /// /// 使用Cookie的购物车 //...
  • ysghyy
  • ysghyy
  • 2011-10-12 21:19
  • 393

vue实例(京东购物车)

今天用vue模仿京东购物车,写了一个简单的购物车, 主要功能有: 1)每一项商品的小计等于商品单价与商品数量的乘积; 2)当商品前面的复选框被选中的时候,计算所有选中的商品的总价和总的数量,该列...
  • huchangjiang0
  • huchangjiang0
  • 2017-08-03 10:28
  • 310

微信小程序 购物车简单实例

微信小程序,这里实现购物车功能的小demo,有需要此功能的朋友可以参考下。 摘要: 加减商品数量,汇总价格,全选与全不选 设计思路: 一、从网络上传入以下Json数据格式的数组 1.购物车i...
  • weixin_38047955
  • weixin_38047955
  • 2017-06-11 04:23
  • 224

【前端开发实例】移动端购物车左滑删除 -(七)

问题实现一个购物车中,左滑商品出现删除按钮的效果。
  • JasonAPoint
  • JasonAPoint
  • 2017-12-16 17:30
  • 205

Ejb in action(四)——购物车实例演示有状态会话Bean

前面,我们介绍了一个入门实例,其实那就是无状态回话Bean的常用情况。 上一篇文章中,我们介绍了无状态会话Bean和有状态会话Bean的相关概念。为了加深大家对它们的理解,我们一起来实现一个有状态会...
  • liu765023051
  • liu765023051
  • 2014-05-13 15:33
  • 2575

组合模式设计购物车价格计算实例(仅供学习使用)

<?php /** *组合模式设计购物车价格计算 * */ abstract class prices { public $price_info = array(); ...
  • i_bruce
  • i_bruce
  • 2014-09-21 13:29
  • 1336
    个人资料
    • 访问:20579次
    • 积分:392
    • 等级:
    • 排名:千里之外
    • 原创:16篇
    • 转载:1篇
    • 译文:0篇
    • 评论:7条
    最新评论