利用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 相关文章推荐
使用jquery中height()方法获取各种高度大全
Apr 02 Javascript
Jquery倒计时源码分享
May 16 Javascript
用js判断是否为360浏览器的实现代码
Jan 15 Javascript
JS验证IP,子网掩码,网关和MAC的方法
Jul 02 Javascript
JS函数的几种定义方式分析
Dec 17 Javascript
js实现下拉列表选中某个值的方法(3种方法)
Dec 17 Javascript
分享有关jQuery中animate、slide、fade等动画的连续触发、滞后反复执行的bug
Jan 10 Javascript
Jquery on绑定的事件 触发多次实例代码
Dec 08 Javascript
Vue内部渲染视图的方法
Sep 02 Javascript
jQuery 图片查看器插件 Viewer.js用法简单示例
Apr 04 jQuery
vue中的循环对象属性和属性值用法
Sep 04 Javascript
vue配置多代理服务接口地址操作
Sep 08 Javascript
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实现数据分页显示功能
2016/05/26 PHP
laravel中短信发送验证码的实现方法
2018/04/25 PHP
jQuery 性能优化指南(2)
2009/05/21 Javascript
Array的push与unshift方法性能比较分析
2011/03/05 Javascript
40款非常有用的 jQuery 插件推荐(系列一)
2011/12/21 Javascript
JS编程小常识很有用
2012/11/26 Javascript
通过一段代码简单说js中的this的使用
2013/07/23 Javascript
js中的push和join方法使用介绍
2013/10/08 Javascript
JS运动基础框架实例分析
2015/03/03 Javascript
使用纯javascript实现经典扫雷游戏
2015/04/23 Javascript
理解JavaScript中Promise的使用
2016/01/18 Javascript
javascript轻量级库createjs使用Easel实现拖拽效果
2016/02/19 Javascript
PHP+jquery+ajax实现分页
2016/12/09 Javascript
vuejs项目打包之后的首屏加载优化及打包之后出现的问题
2018/04/01 Javascript
小程序tab页无法传递参数的方法
2018/08/03 Javascript
vue.js编译时给生成的文件增加版本号
2018/09/17 Javascript
详解Vue中组件的缓存
2019/04/20 Javascript
用Vue.js方法创建模板并使用多个模板合成
2019/06/28 Javascript
JS数组的高级使用方法示例小结
2020/03/14 Javascript
antd的select下拉框因为数据量太大造成卡顿的解决方式
2020/10/31 Javascript
three.js 实现露珠滴落动画效果的示例代码
2021/03/01 Javascript
[01:20]DOTA2 2017国际邀请赛冠军之路无止竞
2017/06/19 DOTA
[08:08]DOTA2-DPC中国联赛2月28日Recap集锦
2021/03/11 DOTA
python进阶教程之循环对象
2014/08/30 Python
在Heroku云平台上部署Python的Django框架的教程
2015/04/20 Python
Python编程之微信推送模板消息功能示例
2017/08/21 Python
详解Python 爬取13个旅游城市,告诉你五一大家最爱去哪玩?
2019/05/07 Python
python实现从本地摄像头和网络摄像头截取图片功能
2019/07/11 Python
Pyinstaller 打包发布经验总结
2020/06/02 Python
如何基于Python实现word文档重新排版
2020/09/29 Python
flask框架中的cookie和session使用
2021/01/31 Python
DELPHI面试题研发笔试试卷
2015/11/08 面试题
大学生活动总结怎么写
2014/04/29 职场文书
忠犬八公的故事观后感
2015/06/05 职场文书
python中的mysql数据库LIKE操作符详解
2021/07/01 MySQL
Java8利用Stream对列表进行去除重复的方法详解
2022/04/14 Java/Android