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, 为什么在这里我们需要使用 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基本知识的就可以理解了。

knockout.js实例二~购物车相关推荐

  1. Three.js实例详解___旋转的精灵女孩(附完整代码和资源)(二)

    Three.js实例详解___旋转的精灵女孩(附完整代码和资源)(二) 本篇目录: 五.实例中所使用的代码语法详细解释 (1).构建一个三维空间场景 (2).选择一个透视投影相机作为观察点 (a).创 ...

  2. MVVM(Knockout.js)的新尝试:多个Page,一个ViewModel

    对于面向数据的Web应用来说,MVVM模式是一项不错的选择,它借助JS框架提供的"绑定"机制是我们无需过多关注UI(HTML)的细节,只需要操作绑定的数据源.MVVM最早被微软应用 ...

  3. 【ASP.NET Web API教程】2.3.5 用Knockout.js创建动态UI

    [ASP.NET Web API教程]2.3.5 用Knockout.js创建动态UI 原文:[ASP.NET Web API教程]2.3.5 用Knockout.js创建动态UI 注:本文是[ASP ...

  4. MVC、MVP、MVVM、Angular.js、Knockout.js、Backbone.js、React.js、Ember.js、Avalon.js、Vue.js 概念摘录...

    注:文章内容都是摘录性文字,自己阅读的一些笔记,方便日后查看. MVC MVC(Model-View-Controller),M 是指业务模型,V 是指用户界面,C 则是控制器,使用 MVC 的目的是 ...

  5. Knockout.js 初探

    Knockout.js是什么? Knockout是一款很优秀的JavaScript库,它可以帮助你仅使用一个清晰整洁的底层数据模型(data model)即可创建一个富文本且具有良好的显示和编辑功能的 ...

  6. jquery.fly.js实现添加购物车效果、实现抛物线运动

    一.JQuery.fly.js整理 1.Git源代码地址: https://github.com/amibug/fly 2.Demo演示地址:http://codepen.io/hzxs1990225 ...

  7. Three.js实例详解___旋转的精灵女孩(附完整代码和资源)(一)

    Three.js实例详解___旋转的精灵女孩(附完整代码和资源)(一) 本文目录: 一.[旋转的精灵女孩]案例运行效果 二.Three.js简介 三.Three.js代码正常运行显示条件 (1)不载入 ...

  8. Knockout.js 整理

    上个月做项目需要用到easyui和Knockout.js ,所以简单的整理了下,以便学习 Knockout.js 是一个JavaScript库,它可以让HTML控件很容易与数据进行绑定.使用的是&qu ...

  9. JS 生成二维码实现(qrcode.js)

    qrcode.js源码地址: https://github.com/jeromeetienne/jquery-qrcode 使用 页面引入QRCode.js和JQuery.js <script ...

最新文章

  1. 《网球王子》与阿梅尔
  2. 状态机在VHDL中的实现
  3. java Ajax cache_ajax之cache血与泪~~
  4. [vue] 在使用计算属性的时,函数名和data数据源中的数据可以同名吗?
  5. python计算执行时间的函数_[python] 统计函数运行时间
  6. 女孩去互联网大厂工作怎么样?
  7. Android ThreadPool
  8. linux dosbox使用教程,dosbox安装及汇编教程 dosbox的常用快捷键
  9. vlan的基本指令_vlan划分命令
  10. java后台实现批量打印功能
  11. 链表哈夫曼树--编码--解码
  12. 微信小程序 教学质量问卷调查 小程序实现
  13. 重学JavaWeb —— JSP,简单全面一发入魂
  14. 数据结构队列之企业级应用--优先队列
  15. KVM安装/libvirt没有启动成功找不到/var/run/libvirt/libvirt-sock
  16. 苹果xr截屏怎么截_苹果系统截屏录屏+标记剪辑功能详解( iPhone/iPad/Mac)
  17. 物流是如何用计算机管理的,计算机信息管理在物流业的应用
  18. Launcher进程启动流程
  19. 基于原版Hadoop的YDB部署
  20. CSS水平垂直居中常见方法总结(转)

热门文章

  1. 将网页上所有canvas下载为图片
  2. Windows / Ubuntu 秒表置顶的方法
  3. 360浏览器怎么截图?
  4. 解决较新版Chrome浏览器跨越的问题
  5. 2.9 PS心得体会
  6. VUE中页面跳转的常用方式及返回上一页实现的两种方式
  7. html超链接技术介绍,HTML超链接
  8. Django 中间件详解
  9. 牛奶们,你们能承受多少宣言?(原创)
  10. HTML标签的语法格式和属性