JavaScript实现类似淘宝的购物车效果


Posted in Javascript onMarch 16, 2017

前言

相信大家都很熟悉商品购物车这一功能,每当我们在某宝某东上购买商品的时候,看中了哪件商品,就会加入购物车中,最后结算。购物车这一功能,方便消费者对商品进行管理,可以添加商品,删除商品,选中购物车中的某一项或几项商品,最后商品总价也会随着消费者的操作随着变化。本文介绍的是通过JavaScript实现类似于淘宝的购物车效果,包括商品的单选、全选、删除、修改数量、价格计算、数目计算、预览等功能。

功能如下

      1. 实现兼容低版本IE的getElementsByClassName()方法

      2. JS表格操作

      3. 通过parseInt()parseFloat()把字符串转换成数字

      4. 通过toFixed()把数字格式化成指定位数的小数

      5. 事件代理的运用

效果图:

JavaScript实现类似淘宝的购物车效果

border-collapse有两个值可以选择,分别是collapse和separate,就是合并边框和分离边框,分离边框之下又可以设置间距和边框样式

border-spacing:2em 4em;(设置右间距和下间距)

border-style:none solid dashed dotted;(分别设置上右下左的样式)

html结构:

<table id="cartTable">
 <thead>
 <tr>
 <th><label><input class="check-all check" type="checkbox"/> 全选</label></th>
 <th>商品</th>
 <th>单价</th>
 <th>数量</th>
 <th>小计</th>
 <th>操作</th>
 </tr>
 </thead>
 <tbody>
 <tr>
 <td class="checkbox"><input class="check-one check" type="checkbox" /></td>
 <td class="goods"><img src="images/1.jpg" alt="" /><span>Casio/卡西欧 EX-TR350</span></td>
 <td class="price">5999.88</td>
 <td class="count"><span class="reduce"></span><input class="count-input" type="text" value="1"/><span class="add">+</span></td>
 <td class="subtotal">5999.88</td>
 <td class="operation"><span class="delete">删除</span></td>
 </tr>
 <tr>
 <td class="checkbox"><input class="check-one check" type="checkbox" /></td>
 <td class="goods"><img src="images/2.jpg" alt="" /><span>Canon/佳能 PowerShot SX50 HS</span></td>
 <td class="price">3888.50</td>
 <td class="count"><span class="reduce"></span><input class="count-input" type="text" value="1"/><span class="add">+</span></td>
 <td class="subtotal">3888.50</td>
 <td class="operation"><span class="delete">删除</span></td>
 </tr>
 <tr>
 <td class="checkbox"><input class="check-one check" type="checkbox" /></td>
 <td class="goods"><img src="images/3.jpg" alt="" /><span>Sony/索尼 DSC-WX300</span></td>
 <td class="price">1428.50</td>
 <td class="count"><span class="reduce"></span><input class="count-input" type="text" value="1"/><span class="add">+</span></td>
 <td class="subtotal">1428.50</td>
 <td class="operation"><span class="delete">删除</span></td>
 </tr>
 <tr>
 <td class="checkbox"><input class="check-one check" type="checkbox" /></td>
 <td class="goods"><img src="images/4.jpg" alt="" /><span>Fujifilm/富士 instax mini 25</span></td>
 <td class="price">640.60</td>
 <td class="count"><span class="reduce"></span><input class="count-input" type="text" value="1"/><span class="add">+</span></td>
 <td class="subtotal">640.60</td>
 <td class="operation"><span class="delete">删除</span></td>
 </tr>
 </tbody>
</table>
<div class="foot" id="foot">
 <label class=" fl select-all"><input type="checkbox" class="check-all check" /> 全选</label>
 <a class="fl delete" id="deleteAll" href="javascript:;" rel="external nofollow" >删除</a>
 <div class="fr closing">结 算</div>
 <div class="fr total">合计:¥<span id="priceTotal">0.00</span></div>
 <div class="fr select" id="selected">已选商品<span id="selectedTotal">0</span>件<span class="arrow up">︽</span><span class="arrow down">︾</span></div>
 <div class="selected-view">
 <div id="selectedViewList" class="clearfix">
 <div><img src="images/1.jpg"><span>取消选择</span></div>
 </div>
 <span class="arrow">◆<span>◆</span></span>
 </div>
</div>

css代码:

*{
 margin: 0;
 padding: 0;
 }
 a{
 color: #666;
 text-decoration: none;
 }
 body{
 padding:20px;
 color: #666;
 }
 .fl{
 float: left;
 }
 .fr{
 float: right;
 }
 table{
 border-collapse: collapse;
 border-spacing: 0;
 border: 0;
 text-align: center;
 width: 937px;
 }
 th,td{
 border: 1px solid #cadeff;
 }
 th{
 background: #e2f2ff;
 border-top: 3px solid #a7cbff;
 height: 30px;
 }
 td{
 padding: 10px;
 color: #444;
 }
 tbody tr:hover{
 background: RGB(238,246,255);
 }
 .checkbox{width: 60px;}
 .goods{width: 300px;}
 .goods span{
 width: 180px;
 margin-top: 20px;
 text-align: left;
 float: left;
 }
 .price{width: 130px;}
 .count{width: 90px;}
 .count .add, .count input, .count .reduce{
 float: left;
 margin-left: -1px;
 position: relative;
 z-index: 0;
 }
 .count .add, .count .reduce{
 height: 23px;
 width: 17px;
 border: 1px solid #e5e5e5;
 background: #f0f0f0;
 text-align: center;
 line-height: 23px;
 color: #444;
 }
 .count .add:hover, .count .reduce:hover{
 color: #f50;
 z-index: 3;
 border-color: #f60;
 cursor: pointer;
 }
 .count input{
 width: 50px;
 height: 15px;
 line-height: 15px;
 border: 1px solid #aaa;
 color: #343434;
 text-align: center;
 padding: 4px 0;
 background-color: #fff;
 z-index: 2;
 }
 .subtotal{
 width: 150px;
 color: red;
 font-weight: bold;
 }
 .operation{width: 80px;}
 .operation span:hover, .a:hover{
 cursor: pointer;
 color: red;
 text-decoration: underline;
 }
 img{
 width: 100px;
 height: 80px;
 margin-right: 10px;
 float: left;
 }
 .foot{
 width: 935px;
 margin-top: 10px;
 color: #666;
 height: 48px;
 border: 1px solid #c8c8c8;
 background-image: linear-gradient(RGB(241,241,241),RGB(226,226,226));
 position: relative;
 z-index: 8;
 }
 .foot div, .foot a{
 line-height: 48px;
 height: 48px;
 }
 .foot .select-all{
 width: 100px;
 height: 48px;
 line-height: 48px;
 padding-left: 5px;
 color: #666;
 }
 .foot .closing{
 border-left: 1px solid #c8c8c8;
 width: 100px;
 text-align: center;
 color: #000;
 font-weight: bold;
 background: RGB(238,238,238);
 cursor: pointer;
 }
 .foot .total{
 margin: 0 20px;
 cursor: pointer;
 }
 .foot #priceTotal, .foot #selectedTotal{
 color: red;
 font-family: "微软雅黑";
 font-weight: bold;
 }
 .foot .select{
 cursor: pointer;
 }
 .foot .select .arrow{
 position: relative;
 top: -3px;
 margin-left: 3px;
 }
 .foot .select .down{
 position: relative;
 top: 3px;
 display: none;
 }
 .show .select .down{
 display: inline;
 }
 .show .select .up{
 display: none;
 }
 .foot .select:hover .arrow{
 color: red;
 }
 .foot .selected-view{
 width: 935px;
 border: 1px solid #c8c8c8;
 position: absolute;
 height: auto;
 background: #fff;
 z-index: 9;
 bottom: 48px;
 left: -1px;
 display: none;
 }
 .show .selected-view{display: block;}
 .foot .selected-view div{height: auto;}
 .foot .selected-view .arrow{
 font-size: 16px;
 line-height: 100%;
 color: #c8c8c8;
 position: absolute;
 right: 330px;
 bottom: -9px;
 }
 .foot .selected-view .arrow span{
 color: #fff;
 position: absolute;
 left: 0;
 bottom: 1px;
 }
 #selectedViewList{
 padding: 20px;
 margin-bottom: -20px;
 }
 #selectedViewList div{
 display: inline-block;
 position: relative;
 width: 100px;
 height: 80px;
 border: 1px solid #ccc;
 margin: 10px;
 }
 #selectedViewList div span{
 display: none;
 color: #fff;
 font-size: 12px;
 position: absolute;
 top: 0;
 right: 0;
 width: 60px;
 height: 18px;
 line-height: 18px;
 text-align: center;
 background: RGBA(0,0,0,.5);
 cursor: pointer;
 }
 #selectedViewList div:hover span{
 display: block;
 }

js部分:

1)实现商品的全选功能及数量和价格的计算

var cartTable = document.getElementById('cartTable');
 var tr = cartTable.children[1].rows;//获取table下的tbody下的每一行
 var checkInputs = document.getElementsByClassName('check');
 var checkAllInputs = document.getElementsByClassName('check-all');
 var selectedTotal = document.getElementById('selectedTotal');
 var priceTotal = document.getElementById('priceTotal');
 //计算总数和价格
 function getTotal(){
 var selected = 0;
 var price = 0;
 for(var i=0;i < tr.length; i++){
 if(tr[i].getElementsByTagName('input')[0].checked){
  selected += parseInt(tr[i].getElementsByTagName('input')[1].value);
  price += parseFloat(tr[i].cells[4].innerHTML);//cells属性为获得tr下面的td
 }
 }
 selectedTotal.innerHTML = selected;
 priceTotal.innerHTML = price.toFixed(2);//保留两位小数
 }
 for(var i=0;i<checkInputs.length;i++){
 checkInputs[i].onclick = function(){
 if(this.className === 'check-all check'){//如果点击的是全选按钮,则使所有按钮的状态和它相同
  for(var j=0;j<checkInputs.length;j++){
  checkInputs[j].checked = this.checked;
  }
 }
 if(this.checked == false){//如果其中一个变为未选中状态,则使全选按钮取消选中
  for(var i=0;i<checkAllInputs.length;i++){
  checkAllInputs[i].checked = false;
  }
 }
 getTotal();
 }
 }

2)点击已选商品实现商品预览浮层的功能

点击已选商品时会显示出已选择商品的列表

同时在getTotal()函数中增加新创建的div

js代码:

function getTotal(){
 var selected = 0;
 var price = 0;
 var HTMLstr = '';
 for(var i=0;i < tr.length; i++){
 if(tr[i].getElementsByTagName('input')[0].checked){
  tr[i].className = 'on';
  selected += parseInt(tr[i].getElementsByTagName('input')[1].value);
  price += parseFloat(tr[i].cells[4].innerHTML);//cells属性为获得tr下面的td
  HTMLstr += '<div><img src="'+ tr[i].getElementsByTagName('img')[0].src + '"><span>取消选择</span></div>';
 }
 else{
  tr[i].className = '';
 }
 }
 selectedTotal.innerHTML = selected;
 priceTotal.innerHTML = price.toFixed(2);//保留两位小数
 selectedViewList.innerHTML = HTMLstr;
 if(selected == 0){
 foot.className = 'foot';
 }
 }
 for(var i=0;i<checkInputs.length;i++){
 checkInputs[i].onclick = function(){
 if(this.className === 'check-all check'){//如果点击的是全选按钮,则使所有按钮的状态和它相同
  for(var j=0;j<checkInputs.length;j++){
  checkInputs[j].checked = this.checked;
  }
 }
 if(this.checked == false){//如果其中一个变为未选中状态,则使全选按钮取消选中
  for(var i=0;i<checkAllInputs.length;i++){
  checkAllInputs[i].checked = false;
  }
 }
 getTotal();
 }
 }

 selected.onclick = function(){
 if(foot.className == 'foot'){
 if(selectedTotal.innerHTML != 0){
  foot.className = 'foot show';
 }
 }else{
 foot.className = 'foot';
 }
 }

 3)商品列表中的取消选择与事件代理

已选商品列表中没有appendChild的时候div和span都不存在,所以要使用事件代理。

selectedViewList.onclick = function(e){
  var el = e.srcElement;
  if(el.className == 'del'){
  var index = el.getAttribute('index');
  var input = tr[index].getElementsByTagName('input')[0];
  input.checked = false;
  input.onclick();
  }
 }

4)实现增减商品数量及小计价格的计算

//增减商品数量事件代理
 for(var i=0;i<tr.length;i++){
  tr[i].onclick = function(e){
  e = e|| window.event;
  var el = e.srcElement;
  var cls = el.className;
  var input = this.getElementsByTagName('input')[1];
  var val = parseInt(input.value);
  var reduce = this.getElementsByTagName('span')[1];
  switch (cls){
   case 'add':
   input.value = val + 1;
   reduce.innerHTML = '-';
    getsubTotal(this);
   break;
   case 'reduce':
   if(val > 1){
    input.value = val - 1;
    getsubTotal(this);
   }else{
    reduce.innerHTML = '';
   }
  }
  getTotal();
  }
  tr[i].getElementsByTagName('input')[1].onkeyup = function(){
  var val = parseInt(this.value);
  var tr = this.parentNode.parentNode;//this指的是当前的input,其父节点的父节点就是当前的tr
  var reduce = tr.getElementsByTagName('span')[1];
  if(isNaN(val) || val < 1){
   val = 1;
  }
  this.value = val;//保证输入框中都是大于1的纯数字
  if(val <= 1){
   reduce.innerHTML = '';
  }
  else{
   reduce.innerHTML = '-';
  }
  getsubTotal(tr);
  getTotal();
  }
 }

 5)实现删除商品功能

学会用for循环删除数组中的一些数据时要回置下标 i 。

//删除商品
 deleteAll.onclick = function(){
  if(selectedTotal.innerHTML != '0'){
  var conf = confirm("确定要删除所选商品吗");
  if(conf){
   for(var i=0;i<tr.length;i++){
   var input = tr[i].getElementsByTagName('input')[0];
   if(input.checked){
    tr[i].parentNode.removeChild(tr[i]);
    i --;//因为删除数组中的一个后,后面的索引就会向前移,此时要让i也向前移一个,回置下标i
   }
   }
   getTotal();
  }
  }
 }

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
学习jquery之一
Apr 27 Javascript
(currentStyle)javascript为何有时用style得不到已设定的CSS的属性
Aug 15 Javascript
JavaScript常用对象的方法和属性小结
Jan 24 Javascript
javascript截取字符串(通过substring实现并支持中英文混合)
Jun 24 Javascript
使用jquery的ajax需要注意的地方dataType的设置
Aug 12 Javascript
javascript中的正则表达式使用详解
Aug 30 Javascript
深入学习JavaScript的AngularJS框架中指令的使用方法
Mar 05 Javascript
JavaScript中的原型继承基础学习教程
May 06 Javascript
基于Vue实现tab栏切换内容不断实时刷新数据功能
Apr 13 Javascript
详谈angularjs中路由页面强制更新的问题
Apr 24 Javascript
AngularJS select设置默认值的实现方法
Aug 25 Javascript
微信{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: 1QoCla0699ns81 ]"}
Oct 12 Javascript
原生js更改css样式的两种方式
Mar 15 #Javascript
js清除浏览器缓存的几种方法
Mar 15 #Javascript
从零开始做一个pagination分页组件
Mar 15 #Javascript
Vuex模块化实现待办事项的状态管理
Mar 15 #Javascript
javascript图片预览和上传(兼容IE)
Mar 15 #Javascript
轻松理解JavaScript之AJAX
Mar 15 #Javascript
jQuery插件ContextMenu自定义图标
Mar 15 #Javascript
You might like
php+mysql实现无限级分类 | 树型显示分类关系
2006/11/19 PHP
php中explode与split的区别介绍
2012/10/03 PHP
PHP上传图片、删除图片简单实例
2016/11/12 PHP
jQuery 行级解析读取XML文件(附源码)
2009/10/12 Javascript
js获取当前页面路径示例讲解
2014/01/08 Javascript
JS交换变量的方法
2015/01/21 Javascript
深入浅析JavaScript中的3DES
2016/08/24 Javascript
bootstrap手风琴折叠示例代码分享
2017/05/22 Javascript
基于angular2 的 http服务封装的实例代码
2017/06/29 Javascript
基于node.js制作简单爬虫教程
2017/06/29 Javascript
JavaScript设计模式之工厂模式和抽象工厂模式定义与用法分析
2018/07/26 Javascript
Python中的匿名函数使用简介
2015/04/27 Python
Python中shutil模块的常用文件操作函数用法示例
2016/07/05 Python
python 3.6 +pyMysql 操作mysql数据库(实例讲解)
2017/12/20 Python
使用Python+Splinter自动刷新抢12306火车票
2018/01/03 Python
详解Django之admin组件的使用和源码剖析
2018/05/04 Python
pandas DataFrame 删除重复的行的实现方法
2019/01/29 Python
python 日期排序的实例代码
2019/07/11 Python
Python FtpLib模块应用操作详解
2019/12/12 Python
jupyter notebook中美观显示矩阵实例
2020/04/17 Python
python 代码实现k-means聚类分析的思路(不使用现成聚类库)
2020/06/01 Python
keras 自定义loss层+接受输入实例
2020/06/28 Python
Python 测试框架unittest和pytest的优劣
2020/09/26 Python
解决virtualenv -p python3 venv报错的问题
2021/02/05 Python
英国在线珠宝店:The Jewel Hut
2017/03/20 全球购物
美国隐形眼镜网:Major Lens
2018/02/09 全球购物
员工培训邀请函
2014/01/11 职场文书
《卖木雕的少年》教学反思
2014/04/11 职场文书
经贸日语专业自荐信
2014/09/02 职场文书
学生实习证明模板汇总
2014/09/25 职场文书
初中教师个人工作总结
2015/02/10 职场文书
新员工试用期自我评价
2015/03/10 职场文书
离婚起诉书范本
2015/05/18 职场文书
行政上诉状范文
2015/05/23 职场文书
《多彩的民间艺术》教学反思
2016/02/16 职场文书
logback如何自定义日志存储
2021/08/30 Java/Android