Javascript实现购物车功能的详细代码
我们肯定都很熟悉商品购物车这一功能,每当我们在某宝某东上购买商品的时候,看中了哪件商品,就会加入购物车中,最后结算。购物车这一功能,方便消费者对商品进行管理,可以添加商品,删除商品,选中购物车中的某一项或几项商品,最后商品总价也会随着消费者的操作随着变化。
现在,笔者对购物车进行了简单实现,能够实现真实购物车当中的大部分功能。在本示例当中,用到了javascript中bom操作,dom操作,表格操作,cookie,json等知识点,同时,采用三层架构方式对购物车进行设计,对javascript的综合应用较强,对javascript初学者进阶有一定的益处。
请看主页效果图:
现在读者已经对主页的效果图进行了了解,我在这里附上主页的html代码,供读者参考,建议读者根据自己的思路写代码。
请看html代码:
<!doctype html> <html> <head> <meta charset="utf-8" /> <title>商品列表页面</title> <!--商品列表样式表--> <link rel="stylesheet" type="text/css" href="../css/index.css" rel="external nofollow" /> <!--cookie操作的js库--> <script src="../js/cookie.js" type="text/javascript" charset="utf-8"></script> </head> <body> <div class="container"> <h1>商品列表</h1> <div class="mycar"> <a href="cart.html" rel="external nofollow" >我的购物车</a><i id="ccount">0</i> </div> <div class="list"> <dl pid="1001"> <dt> <img src="../images/p1.jpg" /> </dt> <dd>智能手表</dd> <dd>酷黑,棒,棒,棒,棒</dd> <dd>¥<span>998</span></dd> <dd> <button>添加购物车</button> </dd> </dl> <dl pid="1002"> <dt> <img src="../images/p2.jpg" /> </dt> <dd>智能手机001</dd> <dd>金红色,酷酷酷酷</dd> <dd>¥<span>1998</span></dd> <dd> <button>添加购物车</button> </dd> </dl> <dl pid="1003"> <dt> <img src="../images/p3.jpg" /> </dt> <dd>华为手机002</dd> <dd>帅帅帅帅帅帅帅帅帅帅</dd> <dd>¥<span>998</span></dd> <dd> <button>添加购物车</button> </dd> </dl> <dl pid="1004"> <dt> <img src="../images/p4.jpg" /> </dt> <dd>华为手机003</dd> <dd>杠杠的</dd> <dd>¥<span>2000</span></dd> <dd> <button>添加购物车</button> </dd> </dl> </div> </div> <!-- 描述:数据访问层,操作本地数据的模块 --> <script type="text/javascript" src="../js/server.js"></script> <!-- 描述:本页面的js操作 --> <script type="text/javascript" src="../js/index.js"></script> </body> </html>
html结构代码有了之后,就可以对主页进行css表现设计,这里不对css进行过多讲解。
我们对主页进行设计之后,就可以进行与主页相关的dom操作,涉及到添加按钮的点击事件,cookie和json的应用,cookie主要为了让当前数据与购物车进行共享,以方便操作。请看与之相关的javascript代码:
这是index.js代码,主要是主页的相关操作:
/* 思路: 第一步:获取所要操作的节点对象 第二步:当页面加载完后,需要计算本地cookie存了多少【个】商品,把个数赋值给ccount 第三步:为每一个商品对应的添加购物车按钮绑定一个点击事件onclick 更改本地的cookie 获取当前商品的pid 循环遍历本地的cookie转换后的数组,取出每一个对象的pid进行对比,若相等则该商品不是第一次添加 从购物车中取出该商品,然后更pcount值追加1 否则:创建一个新的对象,保存到购物中。同时该商品的数量为1 */ var ccount = document.getelementbyid("ccount"); //显示商品总数量的标签节点对象 var btns = document.queryselectorall(".list dl dd button"); //所有的购物车按钮 //约定好用名称为datas的cookie来存放购物车里的数据信息 datas里所存放的就是一个json字符串 var liststr = cookieobj.get("datas"); /*判断一下本地是否有一个购物车(datas),没有的话,创建一个空的购物车,有的话就直接拿来使用*/ if(!liststr) { //没有购物车 datas json cookieobj.set({ name: "datas", value: "[]" }); liststr = cookieobj.get("datas"); } var listobj = json.parse(liststr); //数组 /*循环遍历数组,获取每一个对象中的pcount值相加总和*/ var totalcount = 0; //默认为0 for(var i = 0, len = listobj.length; i < len; i++) { totalcount = listobj[i].pcount + totalcount; } ccount.innerhtml = totalcount; /*循环为每一个按钮添加点击事件*/ for(var i = 0, len = btns.length; i < len; i++) { btns[i].onclick = function() { var dl = this.parentnode.parentnode; var pid = dl.getattribute("pid");//获取自定义属性 var arrs = dl.children;//获取所有子节点 if(checkobjbypid(pid)) { listobj = updateobjbyid(pid, 1) } else { var imgsrc = arrs[0].firstelementchild.src; var pname = arrs[1].innerhtml; var pdesc = arrs[2].innerhtml; var price = arrs[3].firstelementchild.innerhtml; var obj = { pid: pid, pimg: imgsrc, pname: pname, pdesc: pdesc, price: price, pcount: 1 }; listobj.push(obj) listobj = updatedata(listobj); } ccount.innerhtml = gettotalcount(); } }
这是cookie.js的代码,主要涉及cookie的设置获取操作,采用单例设计模式进行了封装设计,请看代码:
/* 单例设计模式 完整形式:[]中是可选项 document.cookie = “name=value[;expires=date][;path=path-to-resource][;domain=域名][;secure]” */ var cookieobj = { /* 增加或修改cookie 参数:o 对象{} name:string cookie名 value:string cookie值 expires:date对象 过期时间 path:string 路径限制 domain:string 域名限制 secure:boolean true https false或undeinfed */ set: function(o) { var cookiestr = encodeuricomponent(o.name) + "=" + encodeuricomponent(o.value); if(o.expires) { cookiestr += ";expires=" + o.expires; } if(o.path) { cookiestr += ";path=" + o.path; } if(o.domain) { cookiestr += ";domain=" + o.domain; } if(o.secure) { cookiestr += ";secure"; } document.cookie = cookiestr; }, /* 删除 参数:n string cookie的名字 */ del: function(n) { var date = new date(); date.sethours(-1); //this代表的是当前函数的对象 this.set({ name: n, expires: date }); }, /*查找*/ get: function(n) { n = encodeuricomponent(n); var cooiketotal = document.cookie; var cookies = cooiketotal.split("; "); for(var i = 0, len = cookies.length; i < len; i++) { var arr = cookies[i].split("="); if(n == arr[0]) { return decodeuricomponent(arr[1]); } } } }
下面的是server.js代码,主要对购物车中各种操作进行了封装,比如商品个数统计,更新获取本地数据等操作,方便代码管理,请看代码:
/* 功能:查看本地数据中是否含有指定的对象(商品),根据id 参数:id:商品的标识 */ function checkobjbypid(id) { var jsonstr = cookieobj.get("datas"); var jsonobj = json.parse(jsonstr); var isexist = false; for(var i = 0, len = jsonobj.length; i < len; i++) { if(jsonobj[i].pid == id) { isexist = true; break; } } return isexist; //return false; } /* 功能:更新本地数据 参数:arr 数组对象 返回一个值:最新的本地转换后的数组对象 * */ function updatedata(arr) { var jsonstr = json.stringify(arr); cookieobj.set({ name: "datas", value: jsonstr }); jsonstr = cookieobj.get("datas"); return json.parse(jsonstr); } /* 获取商品的总数量 返回:数字 */ function gettotalcount() { /*循环遍历数组,获取每一个对象中的pcount值相加总和*/ var totalcount = 0; //默认为0 var jsonstr = cookieobj.get("datas"); var listobj = json.parse(jsonstr); for(var i = 0, len = listobj.length; i < len; i++) { totalcount = listobj[i].pcount + totalcount; } return totalcount; } /* 更新本地数据根据pid id:商品的标识 */ function updateobjbyid(id, num) { var jsonstr = cookieobj.get("datas"); var listobj = json.parse(jsonstr); for(var i = 0, len = listobj.length; i < len; i++) { if(listobj[i].pid == id) { listobj[i].pcount = listobj[i].pcount + num; break; } } return updatedata(listobj) } /* 获取本地数据 返回 数组对象 * */ function getalldata() { var jsonstr = cookieobj.get("datas"); var listobj = json.parse(jsonstr); return listobj; } function deleteobjbypid(id) { var lisobj = getalldata(); for(var i = 0, len = lisobj.length; i < len; i++) { if(lisobj[i].pid == id) { lisobj.splice(i, 1); break; } } updatedata(lisobj); return lisobj; }
因为上述代码中涉及了进入购物车后的一些操作,读者看了之后可能会感动疑惑,不用担心,下面请看点击进入我的购物车之后的分析。
请看效果图:
笔者在主页中点击了三种商品,共点击了七次,在购物车中出现了相应商品以及价格计算。对于途中的各种信息,相信读者一目了然。请看本购物车的html代码:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>购物车</title> <!--购物车样式表--> <link rel="stylesheet" type="text/css" href="../css/cart.css" rel="external nofollow" /> <!--操作cookie的js文件--> <script type="text/javascript" src="../js/cookie.js"></script> </head> <body> <div class="container"> <h1>购物车</h1> <h3><a href="index.html" rel="external nofollow" >返回商品列表页面</a></h3> <table id="table" border="1" cellspacing="0" cellpadding="0" class="hide"> <thead> <tr> <th> <input type="checkbox" id="allcheck" class="ck" />全选 </th> <th> 图片 </th> <th> 描述 </th> <th> 数量 </th> <th> 单价 </th> <th> 小计 </th> <th> 操作 </th> </tr> </thead> <tbody id="tbody"> <!-- <tr> <td> <input type="checkbox" class="ck" /> </td> <td> <img src="../images/p1.jpg" alt="" /> </td> <td> 酷黑,棒棒棒棒 </td> <td> <button class="down">-</button><input type="text" value="1" readonly="readonly" /><button class="up">+</button> </td> <td> ¥<span>111</span> </td> <td> ¥<span>111</span> </td> <td> <button class="del" >删除</button> </td> </tr> --> </tbody> </table> <div class="box" id="box">购物车里没有任何商品</div> <h2 id="h2" class="">总价格:¥<span id="totalprice">0</span></h2> </div> <script src="../js/server.js" type="text/javascript" charset="utf-8"></script> <!--操作购物车页面的cart.js--> <script src="../js/cart.js"></script> </body> </html>
在对购物车进行相关的表现设计之后,既要进行javascript行为设计,请看与本页相关的cart.js代码:
/* 思路: 第一步:当页面加载完后,根据本地的数据,动态生成表格(购物车列表) 获取所要操作的节点对象 判断购物车中是否有数据? 有: 显示出购物列表 没有: 提示购物车为空 第二步:当购物车列表动态生成后,获取tbody里所有 的checkebox标签节点对象,看那个被选中就获取对应行小计进行总价格运算。 第三步: 为每一个checkbox添加一个onchange事件,根据操作更改总价格 第四步:全选 第五步: 为加减按钮添加一个鼠标点击事件 更改该商品的数量 第六步:删除 获取所有的删除按钮 为删除按钮添加一个鼠标点击事件 删除当前行,并更新本地数据 */ var listobj = getalldata(); var table = document.getelementbyid("table") var box = document.getelementbyid("box") var tbody = document.getelementbyid("tbody"); var totalprice = document.getelementbyid("totalprice"); var allcheck = document.getelementbyid("allcheck"); if(listobj.length == 0) { //购物车为空 box.classname = "box"; table.classname = "hide"; } else { box.classname = "box hide"; table.classname = ""; for(var i = 0, len = listobj.length; i < len; i++) { var tr = document.createelement("tr"); tr.setattribute("pid", listobj[i].pid); //{"pid":值,"pimg":值,"pname":值,"pdesc":值,"price":值,"pcount":1}, tr.innerhtml = '<td>' + '<input type="checkbox" class="ck" />' + '</td>' + '<td>' + '<img src="' + listobj[i].pimg + '" alt="" />' + '</td>' + '<td>' + listobj[i].pdesc + '</td>' + '<td>' + '<button class="down">-</button><input type="text" value="' + listobj[i].pcount + '" readonly="readonly" /><button class="up">+</button>' + '</td>' + '<td>' + '¥<span>' + listobj[i].price + '</span>' + '</td>' + '<td>' + '¥<span>' + listobj[i].price * listobj[i].pcount + '</span>' + '</td>' + '<td>' + '<button class="del" >删除</button>' + '</td>'; tbody.appendchild(tr); } } /* 功能:计算总价格 */ var cks = document.queryselectorall("tbody .ck"); function gettotalprice() { cks = document.queryselectorall("tbody .ck"); var sum = 0; for(var i = 0, len = cks.length; i < len; i++) { if(cks[i].checked) { //如果当前被选中 var tr = cks[i].parentnode.parentnode; var temp = tr.children[5].firstelementchild.innerhtml; sum = number(temp) + sum; } } return sum; } /*循环遍历为每一个checkbox添加一个onchange事件*/ for(var i = 0, len = cks.length; i < len; i++) { cks[i].onchange = function() { checkallchecked(); totalprice.innerhtml = gettotalprice(); } } /*全选实现*/ allcheck.onchange = function() { if(this.checked) { for(var i = 0, len = cks.length; i < len; i++) { cks[i].checked = true; } } else { for(var i = 0, len = cks.length; i < len; i++) { cks[i].checked = false; } } totalprice.innerhtml = gettotalprice(); } var downs = document.queryselectorall(".down"); //一组减的按钮 var ups = document.queryselectorall(".up"); //一组加的按钮 var dels = document.queryselectorall(".del"); //一组删除按钮 for(var i = 0, len = downs.length; i < len; i++) { downs[i].onclick = function() { var txtobj = this.nextelementsibling;//下一个兄弟节点 var tr = this.parentnode.parentnode; var pid = tr.getattribute("pid"); txtobj.value = txtobj.value - 1; if(txtobj.value < 1) { txtobj.value = 1; updateobjbyid(pid, 0) } else { updateobjbyid(pid, -1) } tr.children[0].firstelementchild.checked = true; checkallchecked(); var price = tr.children[4].firstelementchild.innerhtml; tr.children[5].firstelementchild.innerhtml = price * txtobj.value; totalprice.innerhtml = gettotalprice(); } ups[i].onclick = function() { var txtobj = this.previouselementsibling;//上一个兄弟节点 var tr = this.parentnode.parentnode; var pid = tr.getattribute("pid"); txtobj.value = number(txtobj.value) + 1; updateobjbyid(pid, 1) tr.children[0].firstelementchild.checked = true; checkallchecked() var price = tr.children[4].firstelementchild.innerhtml; tr.children[5].firstelementchild.innerhtml = price * txtobj.value; totalprice.innerhtml = gettotalprice(); } dels[i].onclick = function() { var tr = this.parentnode.parentnode; var pid = tr.getattribute("pid") if(confirm("确定删除?")) { //remove() 自杀 tr.remove(); listobj = deleteobjbypid(pid); } if(listobj.length == 0) { //购物车为空 box.classname = "box"; table.classname = "hide"; } else { box.classname = "box hide"; table.classname = ""; } totalprice.innerhtml = gettotalprice(); } } /*检测是否要全选*/ function checkallchecked() { var isselected = true; //全选是否会选中 for(var j = 0, len = cks.length; j < len; j++) { if(cks[j].checked == false) { isselected = false; break; } } allcheck.checked = isselected; }
上述代码完成了购物车中的相关操作,比如价格计算,商品数量更换,商品删除等操作。
到这里我们已经完成了购物车的大部分功能,我们对html,css, bom,dom,json,cookie等进行了综合应用,相信读者理解之后一定会对自己的javascript学习更进一步,本示例中涉及的大部分代码都在本页中贴出,部分代码资源未向读者展示,读者可以点击下面的资源链接,下载本示例的全部代码及图片资料。本示例采用hbuilder编译器编译运行,涉及cookie操作,请读者自行安装服务器或者添加到hbuilder中运行查看。
资源链接:购物车全部资源下载
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 详解SQL EXISTS 运算符