利用Angularjs和bootstrap实现购物车功能


Posted in Javascript onAugust 31, 2016

先来看看效果图:

利用Angularjs和bootstrap实现购物车功能
购物车

一、代码

如果看了这个效果有兴趣想知道怎么做出来的话,那就继续往下看吧。话不多少,直接上代码。

html代码:

<!DOCTYPE html>
<html lang="en" ng-app="cart">
<head>
 <meta charset="UTF-8">
 <title>购物车</title>
 <link rel="stylesheet" href="../scripts/angular-1.4.0-rc.2/docs/components/bootstrap-3.1.1/css/bootstrap.min.css">
 <link rel="stylesheet" href="main.css">
</head>
<body ng-controller="cartCtr">
<table class="table table-hover" ng-show="items.length">
 <caption>AngularJS实现购物车</caption>
 <tr>
 <th>序号</th>
 <th>商品信息</th>
 <th>单价(元)</th>
 <th>数量</th>
 <th>金额(元)</th>
 <th>操作</th>
 </tr>
 <tr ng-repeat=" item in items">
 <td>{{$index + 1}}</td>
 <td><a href="{{item.linkUrl}}" target="_blank" title="此链接将跳转到淘宝相关页面...">{{item.title}}</a></td>
 <td class="bold">{{item.price|number:2}}</td>
 <td>
  <button type="button" class="btn btn-default btn-xs" ng-click="reduce(item.id)" ng-disabled="item.quantity<=1">-</button>
  <input type="text" size="5" ng-model="item.quantity" ng-keydown="quantityKeydown()" ng-keyup="quantityKeyup()">
  <button type="button" class="btn btn-default btn-xs" ng-click="add(item.id)">+</button>
 </td>
 <td class="bold mark">{{item.price*item.quantity|number:2}}</td>
 <td>
  <button type="button" class="btn btn-default btn-xs" ng-click="delete(item.id)">删除</button>
 </td>
 </tr>
</table>
<div class="empty" ng-show="!items.length">购物车空空,快去寻找宝贝</div>
<div class="total">
 已选商品:<span>{{getQuantites()}} </span>
 合计:
 <span class=" mark" ng-show="getTotalAmount()<15000">{{getTotalAmount()|number:2}}</span>
 <span class=" mark" ng-show="getTotalAmount()>=15000">
 {{getTotalAmount()*discount|number:2}}<span class="btn btn-xs">(9折)</span>
 <span class="discount">({{getTotalAmount()|number:2}})</span>
 </span>
 <button type="button" class="btn btn-primary btn-sm" ng-click="alertSubmit()">结 算</button>
</div>
<script src="../scripts/angular-1.4.0-rc.2/angular.js"></script><script src="app.js"></script>
</body>
</html>

js代码:

/ Created by wqq on 2016/5/25. /
var cartModule = angular.module('cart', []);
cartModule.controller('cartCtr', ['$scope', function ($scope) {
 $scope.discount = 0.9;
 $scope.items = [{id: 10001,title: "Web全栈工程师的自我修养 余果", price: 40.80,quantity: 2,linkUrl: "https://detail.tmall.com/item.htm?spm=a1z0d.6639537.1997196601.4.cwywJs&id=532166746631"},
     {id: 10002,title: "MacBook Pro Retina 15英寸", price: 16088.00,quantity: 1,linkUrl: "https://detail.tmall.com/item.htm?spm=a1z0d.6639537.1997196601.26.cwywJs&id=45771116847"},
     {id: 10003,title: "Surface Book I5 128G 独显",price: 11088.00, quantity: 1,linkUrl: "https://detail.tmall.com/item.htm?spm=a1z0d.6639537.1997196601.15.cwywJs&id=525614504276"},
     {id: 10004, title: "Lenovo Yoga3Pro I5 4G",price: 7299.00, quantity: 1,linkUrl: "https://detail.tmall.com/item.htm?spm=a1z0d.6639537.1997196601.37.cwywJs&id=41541519814"} ];
 $scope.add = function (id) {
  angular.forEach($scope.items, function (item, index, array) {
        if (item.id === id) {item.quantity++;} })
 };
 $scope.reduce = function (id) {
  angular.forEach($scope.items, function (item, index, array) {
        if (item.id === id) {item.quantity--; } })
 };
 //输入框添加keydown事件,避免输入非正整数
 $scope.quantityKeydown = function (event) {
  event = event || window.event;
  var target=event.target||event.srcElement;
  var keycode = event.keyCode;
  if ((37 <= keycode && keycode <= 40)||(48 <= keycode && keycode <= 57) || (96 <= keycode && keycode <= 105) || keycode == 8) {
    //方向键↑→ ↓←、数字键、backspace
  }
  else {
   console.log(keycode);
   event.preventDefault();
   return false;
  }
 };
//keyup事件,当输入数字为0时,重新刷新文本框内容
$scope.quantityKeyup = function (event) {
  event = event || window.event;
  var target=event.target||event.srcElement;
  var keycode = event.keyCode;
  if (48 === keycode || 96 === keycode ) {
   target.value=parseInt(target.value);
 }};
 //删除商品
 $scope.delete = function (id) {
  $scope.items.forEach(function (item, index) {
  if (item.id == id) {
   if (confirm("确定要从购物车中删除此商品?")) {
    $scope.items.splice(index, 1);
    return;
   }
  }
 })
 };
 //计算已选商品数量
 $scope.getQuantites = function () {
 var quantities = 0;
 angular.forEach($scope.items, function (item, index, array) {
  if (item.quantity) {
   quantities += parseInt(item.quantity);
  }
 });
 return quantities;
 };
 //计算合计总金额
 $scope.getTotalAmount = function () {
 var totalAmount = 0;
 angular.forEach($scope.items, function (item, index, array) {
  totalAmount += item.quantity * item.price;  });
 return totalAmount;
 };
 $scope.alertSubmit = function () {alert("Angular实现购物车"); }
}]);

二、分析

请忽略bootstrap的样式,我们只关注Angular,代码很简单,我们来简单的分析一下:

1. 准备

首先我们我们定义了一个cart模块、cartCtr控制器,并将它们引入到了html代码中,同时我们还在js中定义了一个数组items用于模拟购物车内的东西。

2. ng-repeat迭代器

为了将items里的数据动态的遍历加载出来,我们使用Angular里的内置指令ng-repeat,它可以非常方便的遍历数组,生成DOM元素,在这里循环生成了4个<tr>标签:

<tr ng-repeat=" item in items">

item就是items数组里面的某一个对象,是不是感觉这就是js中的for/in循环~~如果你是一名.net开发人员,用过asp.net mvc的Razor就对这种其他语言无缝操作DOM元素很熟悉了,至于java、PHP是否有没有类似的语法我就不清楚了,我是一名苦逼的.net开发。

利用Angularjs和bootstrap实现购物车功能
ng-repeat迭代器

我们可以看到第一个td中用到了$index,这是ng-repeat内的,并不是我们定义的,它的值是当前itemitems中的索引,从0开始,所以我们用$index+1作为序号,其他的还有(类似item.linkUrl)数据绑定。

我们在单价和金额两列用到了{{ xxx|number:2}},这是Angular中的一种过滤器,作用是将前面的值xxx保留两位小数,金额嘛,我们当然要精确一些。刚才说了这是一种过滤器,那就还有其他的,比如currency,可以在xxx前面添加一个$符号表示美元,可以自行百度其他过滤器用法。

3. 添加事件

当前界面上分别有数量+、-按钮、删除按钮,这几个事件都比较简单,利用ng-click给元素添加点击事件。通过传递某个商品的id,找到这个商品,对这个商品进行加、减、删除操作,只不过在“-”按钮上有添加了一个ng-disabled标签,根据名字我们就可以很容易想到html的disabled属性,它的作用就是当ng-disabled的值为true时DOM元素禁用,同理,下面用到的ng-show也是一样的,true时显示,false时隐藏。如果是数字的话会自动转化为boolean值,0是false,非0是true,注意负数也是true!。这里我让当数量为1时就不能减少了,因为再少就可以直接删除了呀~

然后在input元素添加ng-keydown事件,使其只能输入方向键↑→ ↓←、数字键、backspace。然后我试了下确实到达了目的,但是却可以输入类似“00021”这种数字,显然这并不能令人满意。我看了看淘宝的购物车,发现当在前面输入0时,这个文本框的内容会自动刷新,去掉前面的0,于是我又添加了ng-keyup事件:

$scope.quantityKeyup = function (event) {
  event = event || window.event; //兼容IE8以下,target也是
  var target=event.target||event.srcElement;
  var keycode = event.keyCode;
  if (48 === keycode || 96 === keycode ) {
   target.value=parseInt(target.value);
 }};

这时当我输入0时,文本框值就会自动刷新,为什么不添加到keydown里面而要另外再加一个事件呢?那是因为触发keydown事件时target.value的值还是原来的值,还没有包含本次输入的按键,而在keydown之后值就是新值了,这时候我们接着让触发keyup事件就可以达到目的了,可以对照看下淘宝购物车的效果,我觉得我的体验比它的更好,因为它只要不是在最后输入数字文本框总是会失去焦点。。。

4. 统计

统计数量就是直接绑定方法,遍历数组返回值。

合计金额这块,我做了个满15000打9折的设计。利用ng-show隐藏显示带打折信息的合计金额。

三、总结

js中用到了几处forEach遍历数组,ECMAScript5中原生的方法是array.forEach(function(item,index,array){});

angular中也封装了,angular.forEach(array,function(item,index,array){});

代码中我两种方法都用到了,也不知道那种性能好。。

至此,购物车就已经完成了,利用Angular的双向绑定,可以快速的实现数量、金额的联动改变。希望这篇文章的内容对大家学习和使用Angular能有所帮助,如果有疑问可以留言交流。

Javascript 相关文章推荐
JavaScript中的事件处理
Jan 16 Javascript
JavaScript 开发中规范性的一点感想
Jun 23 Javascript
jquery动态增加text元素以及删除文本内容实例代码
Jul 01 Javascript
JavaScript中检测变量是否存在遇到的一些问题
Nov 11 Javascript
jQuery获得指定元素坐标的方法
Apr 14 Javascript
JavaScript访问字符串中单个字符的两种方法
Jul 03 Javascript
JavaScript实现点击按钮切换网页背景色的方法
Oct 17 Javascript
基于jquery实现图片上传本地预览功能
Jan 08 Javascript
vue的滚动条插件实现代码
Sep 07 Javascript
微信小程序vant弹窗组件的实现方式
Feb 21 Javascript
JavaScript实现移动端弹窗后禁止滚动
May 25 Javascript
Vue组件生命周期运行原理解析
Nov 25 Vue.js
JavaScript String(字符串)对象的简单实例(推荐)
Aug 31 #Javascript
基于JavaScript实现鼠标向下滑动加载div的代码
Aug 31 #Javascript
Node.js配合node-http-proxy解决本地开发ajax跨域问题
Aug 31 #Javascript
jQuery禁用快捷键例如禁用F5刷新 禁用右键菜单等的简单实现
Aug 31 #Javascript
基于JavaScript实现点击页面任何位置返回
Aug 31 #Javascript
jquery datatable服务端分页
Aug 31 #Javascript
关于javascript原型的修改与重写(覆盖)差别详解
Aug 31 #Javascript
You might like
社区(php&amp;&amp;mysql)二
2006/10/09 PHP
php截取字符串之截取utf8或gbk编码的中英文字符串示例
2014/03/12 PHP
Python中使用django form表单验证的方法
2017/01/16 PHP
laravel-admin 管理平台获取当前登陆用户信息的例子
2019/10/08 PHP
phpQuery采集网页实现代码实例
2020/04/02 PHP
SOSO地图JS画出标注和中心点以html形式运行
2013/08/09 Javascript
深入理解javascript中defer的作用
2013/12/11 Javascript
jquery根据锚点offset值实现动画切换
2014/09/11 Javascript
jQuery UI插件自定义confirm确认框的方法
2015/03/20 Javascript
基于jQuery实现网页打印功能
2015/12/01 Javascript
Backbone.js框架中简单的View视图编写学习笔记
2016/02/14 Javascript
canvas简单快速的实现知乎登录页背景效果
2017/05/08 Javascript
html5+canvas实现支持触屏的签名插件教程
2017/05/08 Javascript
vue添加axios,并且指定baseurl的方法
2018/09/19 Javascript
深入理解react-router 路由的实现原理
2018/09/26 Javascript
[01:55]TI9显影之尘系列 - Evil Geniuses
2019/08/22 DOTA
python实现dict版图遍历示例
2014/02/19 Python
Python编程之列表操作实例详解【创建、使用、更新、删除】
2017/07/22 Python
python绘制漏斗图步骤详解
2019/03/04 Python
使用PyInstaller将Pygame库编写的小游戏程序打包为exe文件及出现问题解决方法
2019/09/06 Python
python中的Elasticsearch操作汇总
2019/10/30 Python
具有防紫外线功能的高性能钓鱼服装:Hook&Tackle
2018/08/16 全球购物
俄罗斯园林植物网上商店:Garshinka
2020/07/16 全球购物
医学实习生自我鉴定
2013/12/12 职场文书
小学生感恩老师演讲稿
2014/08/28 职场文书
机关干部四风问题自我剖析及整改措施
2014/10/26 职场文书
群众路线教育实践活动学习心得体会
2014/10/30 职场文书
网络营销计划
2015/01/17 职场文书
行政人事专员岗位职责
2015/04/07 职场文书
2015年林业工作总结
2015/05/14 职场文书
2015年秋季运动会广播稿
2015/08/19 职场文书
争做文明公民倡议书
2019/06/24 职场文书
公司要求试用期员工提交“述职报告”,该怎么写?
2019/07/17 职场文书
pandas DataFrame.shift()函数的具体使用
2021/05/24 Python
Redis Stream类型的使用详解
2021/11/11 Redis
CSS 实现磨砂玻璃(毛玻璃)效果样式
2023/05/21 HTML / CSS