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 相关文章推荐
jqPlot 基于jquery的画图插件
Apr 26 Javascript
利用jq让你的div居中的好方法分享
Nov 21 Javascript
封装好的一个万能检测表单的方法
Jan 21 Javascript
浅谈jQuery构造函数分析
May 11 Javascript
jQuery中JSONP的两种实现方式详解
Sep 26 Javascript
微信js-sdk上传与下载图片接口用法示例
Oct 12 Javascript
bootstrapValidator自定验证方法写法
Dec 01 Javascript
Node做中转服务器转发接口
Oct 18 Javascript
JS实现十字坐标跟随鼠标效果
Dec 25 Javascript
javascript面向对象三大特征之多态实例详解
Jul 24 Javascript
vue之延时刷新实例
Nov 14 Javascript
Openlayers3实现车辆轨迹回放功能
Sep 29 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
终于听上了直流胆调频
2021/03/02 无线电
PHP截取中文字符串的问题
2006/07/12 PHP
php htmlspecialchars()与shtmlspecialchars()函数的深入分析
2013/06/05 PHP
PHP内存缓存Memcached类实例
2014/12/08 PHP
php实现的mysqldb读写分离操作类示例
2017/02/07 PHP
php简单实现单态设计模式的方法分析
2017/07/28 PHP
浅谈PHP中如何实现Hook机制
2017/11/14 PHP
JavaScript中Object和Function的关系小结
2009/09/26 Javascript
基于Jquery实现的一个图片滚动切换
2012/06/21 Javascript
关于删除时的提示处理(确定删除吗)
2013/11/03 Javascript
js兼容pc端浏览器并有多种弹出小提示的手机端浮层控件实例
2015/04/29 Javascript
基于JS代码实现当鼠标悬停表格上显示这一格的全部内容
2016/06/12 Javascript
PHP捕捉异常中断的方法
2016/10/24 Javascript
微信小程序  网络请求API详解
2016/10/25 Javascript
基于JS实现翻书效果的页面切换样式
2017/02/16 Javascript
Vue axios 中提交表单数据(含上传文件)
2017/07/06 Javascript
webpack 2的react开发配置实例代码
2017/07/28 Javascript
redux-saga 初识和使用
2018/03/10 Javascript
JS简单获取并修改input文本框内容的方法示例
2018/04/08 Javascript
利用nodeJs anywhere搭建本地服务器环境的方法
2018/05/12 NodeJs
vue中解决chrome浏览器自动播放音频和MP3语音打包到线上的实现方法
2020/10/09 Javascript
[48:52]DOTA2上海特级锦标赛A组小组赛#2 Secret VS CDEC第一局
2016/02/25 DOTA
Python网络编程中urllib2模块的用法总结
2016/07/12 Python
python flask实现分页的示例代码
2018/08/02 Python
对python Tkinter Text的用法详解
2018/10/11 Python
Pandas 按索引合并数据集的方法
2018/11/15 Python
python paramiko利用sftp上传目录到远程的实例
2019/01/03 Python
Python math库 ln(x)运算的实现及原理
2019/07/17 Python
pyinstaller打包opencv和numpy程序运行错误解决
2019/08/16 Python
postman和python mock测试过程图解
2020/02/22 Python
实现CSS3中的border-radius(边框圆角)示例代码
2013/07/19 HTML / CSS
运动会通讯稿300字
2014/02/02 职场文书
司法局群众路线教育实践活动整改措施
2014/09/17 职场文书
2014小学数学教师个人工作总结
2014/12/18 职场文书
证婚人致辞精选
2015/07/28 职场文书
奥特曼十大神器:奥特手镯在榜,第一是贝利亚的神器
2022/03/18 日漫