相信大家在做电商网站的时候,最常见印象最深当属购物车了,有了它我们才可以统计客户选购的商品,然后进行下面收款发货功能,那么购物车这个功能,我们应该怎样通过js给他实现呢,下面让我通过本地存储给大家模仿一个简易的购物车功能吧。
首先我们先分析一下,购物车的前提是需要有一个商城,它包含很多的商品,任由我们来选择,然后当我们点击购物车时,购物车里会显示我们刚刚选择的商品数据。所以我们分两部分来写,首先简单写一个商城把。
一.商城
html部分
<h2>欢迎来到商城,请选购商品 <a href="购物车.html">点击进入购物车</a></h2>
<div class="cont"></div>
css部分
.cont{width: 1000px;margin: 30px auto;border: 1px solid black;overflow: hidden;}
.cont .goods{width:250px;float: left;border: 1px solid black;box-sizing: border-box;text-align: center;}
.goods img{width: 80%;}
.goods span{display: block;margin: 10px 0;}
.goods p{height: 40px;line-height: 20px;overflow: hidden;}
.goods input{display: block;margin: 0 auto;font-size: 20px;}
js部分
1.我们事先准备一个数组,把我们一些商品的数据储存起来,这样的好处,有利于我们以后对于商品数据的添加和更换
//定义一个商品数组
var data = [{
img:"https://img12.360buyimg.com/n7/jfs/t1/94329/20/12711/106212/5e4a97bcE66a103ae/721ae0eaf9ecbaa7.jpg",
price:"1999.00",
name:"荣耀20S 李现同款 3200万人像超级夜景 4800万超广角AI三摄 麒麟810 全网通版6GB+128GB 蝶羽蓝",
goodsId:"123asd"
},{
img:"https://img10.360buyimg.com/n7/jfs/t1/93499/17/90/221850/5da6d4ebE9747a490/8b167328e1dadff8.jpg",
price:"2199.00",
name:"【品质好物】5000mAh大电量,支持18W快充,Type-C充电接口!【K305G爆品开售,点击选购】",
goodsId:"ajgjgj"
},{
img:"https://img12.360buyimg.com/n7/jfs/t1/103980/26/12527/248017/5e4a6b2bEde93b893/af9f1eb0617ce599.jpg",
price:"2399.00",
name:"这是一个手机,看着像手机就行,这是名字",
goodsId:"12u3"
},{
img:"https://img10.360buyimg.com/n7/jfs/t11266/172/3136897597/311385/898550cb/5ce41430N7bb10f75.jpg",
price:"1899.00",
name:"这也是个手机,这是这个手机的名字",
goodsId:"afa876"
}];
2.接下来我们需要的就是把这些数据,放在我们一开始定义的盒子里,完成一个商品展示的效果。
class GoodsList{
// 1.构造函数
constructor(){
this.data = data;
this.cont = document.querySelector(".cont");
}
// 2.事件绑定
init(){
// 3.准备一个空字符串
var str = "";
for(var i = 0;i<this.data.length;i++){
// 4.通过遍历商品数组,把商品属性添加到空数组中
str += `<div class="goods" index="${this.data[i].goodsId}">
<img src="${this.data[i].img}" alt="">
<span>${this.data[i].price}</span>
<p>${this.data[i].name}</p>
<input type="button" value="加入购物车" class="add">
</div>`
}
// 5.把商品添加后在大框中显示
this.cont.innerHTML = str;
}
直到这里我们可以先创建一个实例对象,来看看我们的效果。
// 6.可以先创建实例对象查看
var gl = new GoodsList();
gl.init();
gl.addEvent();
这样我们一个初始的商城雏形就出来了,我们再进行一下分析:
既然我们需要通过点击商品到购物车,我们通过每个商品不同的id,方便把不同的商品进行分开区别。然后当点击商品后,存储在本地数据,进行判断如果本地存储中已经有了这个商品的数据,我们可以不需要再次获得它的数据,我们只需要的是把对应商品的数量+1即可。如果没有点击过此商品,我们就可以通过获取商品的数据在本地存储。
// 7.准备点击购买商品时,把数据本地储存
// 7.1因为事先大框中没有input元素,现在我们需要点击购买按钮,所以需要事件委托的方法
addEvent(){
var that = this;
this.cont.onclick = function(eve){
var e = eve || window.event;
var tar = e.target ||e.srcElement;
// 7.2判断如果选择到input元素,获取它的父元素的属性“index";
if(tar.className == "add"){
that.goodsId = tar.parentNode.getAttribute("index");
// 7.3开始进行本地存储数据
that.setData();
}
}
}
// 8.本地存储数据
setData(){
// 8.1读取goodsMsgs数据
var gm = localStorage.getItem("goodsMsg");
// 8.2判断本地是否有这个数据(数据所在的数组),没有那么就存储
if(gm == null){
// 8.3没有就创建
gm = [{
goodsId:this.goodsId,
num:1,
msg:this.getData(this.goodsId)
}]
}
else{
// 8.4把数组json变成对象类型,方便直接获取属性
gm = JSON.parse(gm);
var zhuangtai = 0;
// 8.5判断存入的数据是否在数组中有,有的话加数量,没有的话把这个数据放到数组中
for(var i = 0;i<gm.length;i++){
if(gm[i].goodsId == this.goodsId){
gm[i].num++;
zhuangtai = 1;
break;
}
}
// 8.6 表示数组中没有此数据,添加进去
if(zhuangtai == 0){
gm.push({
goodsId:this.goodsId,
num:1,
// 8.7 通过传入的goodsid在getData()方法中,如果传入的数据=对应数据的id,那么就把对应的数据拿过来
msg:this.getData(this.goodsId)
})
}
}
//9.以上这个if里面只是在判断操作获取到的数据,并没有存回去,所以最终操作完之后,需要将数据存到本地存储中
localStorage.setItem("goodsMsg",JSON.stringify(gm));
}
// 主要的作用是可以通过点击对应商品,获取商品id,然后遍历整个数据然后找到对应id所贮备的数据
// // 单独封装为了方便获取所有数据中,某个数据的功能
// // 根据传入的id获取
getData(id){
//遍历的时候,比较,符合,返回这个数据(判断是否有这个数据)
for(var i = 0;i<this.data.length;i++){
if(this.data[i].goodsId ==id){
return this.data[i];
}
}
//没有符合,返回空对象,保持数据格式一致
return {};
}
//
}
做到这步的时候我们可以测试一下,看点击商品时,是否能达到我们预想的效果,看本地存储中是否有我们的数据。
一开始我们并没有数据,所以我们需要点击进行存储。
当我们把商品加入购物车时,我们本地存储中已经有了我们每个商品对应的数据,而且当多次点击一个商品时,也并没有重新获取其数据,而是把对应的数量进行了叠加,此时我们商场的效果已经做到了,接下来就是进行购物车功能实现。
二、购物车
html部分
<h2>这是购物车 <a href="商城商品展示.html">点击返回商城</a></h2>
<table border=1 width = 800px align = "center">
<thead>
<tr>
<th>图片</th>
<th>名字</th>
<th>单价</th>
<th>数量</th>
<th>总价</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
css部分
img{width: 100px;height: 100px;}
分析:需要满足购物车功能,我们首先做得就是需要拿到用户已经准备买的商品,也就是我们需要拿到本地存储中的数据,然后将其展现到页面上形成一个初步的雏形。
class Car{
// 1.构造函数
constructor(){
this.tbody = document.querySelector("tbody");
}
// 2.从本地存储中拿到数据,准备在购物车页面显示
getData(){
// 2.1 立即拿到数据
if(localStorage.getItem("goodsMsg")){
// 2.2把其变为json对象格式,方便于调用其中的属性
this.gm = JSON.parse(localStorage.getItem("goodsMsg"));
}
else{
this.gm = [];
}
//3.准备渲染页面
this.display();
}
display(){
// 3.1 准备一个空字符串
var str = "";
// 3.2把数据填入字符串中,准备放到页面上
for(var i=0;i<this.gm.length;i++){
str += `<tr index="${this.gm[i].goodsId}">
<td><img src="${this.gm[i].msg.img}" alt=""></td>
<td>${this.gm[i].msg.name}</td>
<td>${this.gm[i].msg.price}</td>
<td><input type="number" min="1" value="${this.gm[i].num}" class="number"></td>
<td>${ this.gm[i].msg.price * this.gm[i].num }</td>
<td class="delete">删除</td>
</tr>`;
}
// 3.3渲染
this.tbody.innerHTML = str;
}
}
我们创建一个实例对象来看一下初步效果
//4.先创建实例对象进行页面查看
var c = new Car();
c.getData();
接下来就可以对我们的功能进行一下补充和完善。
功能1:删除功能
可以想到,当我们的用户发现错点了商品时,这时需要把购物车中的错误商品给删除掉,这时,我们需要做的就是在界面上去掉错误商品的显示,以及把存储在本地存储的数据给删除掉。
//事件绑定
addEvent(){
var that = this;
// 4.删除功能
// 4.1因为我们一开始在html中并没有删除,所以需要用到事件委托
this.tBody.onclick = function(eve){
var e = eve || window.event;
var tar = e.target || e.srcElement;
if(tar.className == "delete" ){
// 4.2先获取当前点击删除按钮的商品的id
that.id = tar.parentNode.getAttribute("index");
// 4.3删除对应DOM元素
tar.parentNode.remove();
// 4.5删除对应存储在本地的数据
that.changeData(function(i){
that.gm.splice(i,1);
});
}
}
}
// 4.4通过点击获取的商品的id来找到本地存储中对应商品
changeData(cb){
// 根据点击的商品的id查找本地存储的数据中符合的商品数据
for(var i=0;i<this.gm.length;i++){
if(this.gm[i].goodsId === this.id){
cb(i);
break;
}
}
// 剔除掉之后,得再存回去,否则仅仅是在内存中修改,没有修改本地存储
localStorage.setItem("goodsMsg",JSON.stringify(this.gm));
}
}
这时我们可以检测一下是否已经达到了删除功能的效果:
当我们点击删除了最后一个商品时,这时对应商品已经从页面上去除了,
再让我们看一下本地存储
最后一个商品的数据跟随着我点了删除后,从本地存储中也删除掉了。
功能二:总价跟着数量进行改变
//5.总价跟着数量而改变
// 5.1首先也是通过事件委托拿到数量
this.tBody.oninput = function(eve){
var e = eve || window.event;
var tar = e.target || e.srcElement;
if(tar.className === "number"){
//5.2.获取要修改数量的商品的id
that.id = tar.parentNode.parentNode.getAttribute("index");
// 5.3.执行修改本地存储中数据的功能
that.changeData(function(i){
that.gm[i].num = tar.value;
});
// 5.4每次修改数量时,来计算总价
tar.parentNode.nextElementSibling.innerHTML = tar.value * tar.parentNode.previousElementSibling.innerHTML;
}
}
}
下面我们来测试一下功能:
当我们通过改变数量时,总价跟随着本地存储中的数量一起改变了,实现了我们预想的功能。
这样一个初步的购物车就完成了,下面分享一下商城和购物车的总体代码,方便大家去测试和理解。
商城
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
.cont{width: 1000px;margin: 30px auto;border: 1px solid black;overflow: hidden;}
.cont .goods{width:250px;float: left;border: 1px solid black;box-sizing: border-box;text-align: center;}
.goods img{width: 80%;}
.goods span{display: block;margin: 10px 0;}
.goods p{height: 40px;line-height: 20px;overflow: hidden;}
.goods input{display: block;margin: 0 auto;font-size: 20px;}
</style>
</head>
<body>
<h2>欢迎来到商城,请选购商品 <a href="购物车.html">点击进入购物车</a></h2>
<div class="cont"></div>
</body>
<script type="text/javascript">
// 定义一个商品数组
var data = [{
img:"https://img12.360buyimg.com/n7/jfs/t1/94329/20/12711/106212/5e4a97bcE66a103ae/721ae0eaf9ecbaa7.jpg",
price:"1999.00",
name:"荣耀20S 李现同款 3200万人像超级夜景 4800万超广角AI三摄 麒麟810 全网通版6GB+128GB 蝶羽蓝",
goodsId:"123asd"
},{
img:"https://img10.360buyimg.com/n7/jfs/t1/93499/17/90/221850/5da6d4ebE9747a490/8b167328e1dadff8.jpg",
price:"2199.00",
name:"【品质好物】5000mAh大电量,支持18W快充,Type-C充电接口!【K305G爆品开售,点击选购】",
goodsId:"ajgjgj"
},{
img:"https://img12.360buyimg.com/n7/jfs/t1/103980/26/12527/248017/5e4a6b2bEde93b893/af9f1eb0617ce599.jpg",
price:"2399.00",
name:"这是一个手机,看着像手机就行,这是名字",
goodsId:"12u3"
},{
img:"https://img10.360buyimg.com/n7/jfs/t11266/172/3136897597/311385/898550cb/5ce41430N7bb10f75.jpg",
price:"1899.00",
name:"这也是个手机,这是这个手机的名字",
goodsId:"afa876"
}];
class GoodsList{
// 1.构造函数
constructor(){
this.data = data;
this.cont = document.querySelector(".cont");
}
// 2.事件绑定
init(){
// 3.准备一个空字符串
var str = "";
for(var i = 0;i<this.data.length;i++){
// 4.通过遍历商品数组,把商品属性添加到空数组中
str += `<div class="goods" index="${this.data[i].goodsId}">
<img src="${this.data[i].img}" alt="">
<span>${this.data[i].price}</span>
<p>${this.data[i].name}</p>
<input type="button" value="加入购物车" class="add">
</div>`
}
// 5.把商品添加后在大框中显示
this.cont.innerHTML = str;
}
// 7.准备点击购买商品时,把数据本地储存
// 7.1因为事先大框中没有input元素,现在我们需要点击购买按钮,所以需要事件委托的方法
addEvent(){
var that = this;
this.cont.onclick = function(eve){
var e = eve || window.event;
var tar = e.target ||e.srcElement;
// 7.2判断如果选择到input元素,获取它的父元素的属性“index";
if(tar.className == "add"){
that.goodsId = tar.parentNode.getAttribute("index");
// 7.3开始进行本地存储数据
that.setData();
}
}
}
// 8.本地存储数据
setData(){
// 8.1读取goodsMsgs数据
var gm = localStorage.getItem("goodsMsg");
// 8.2判断本地是否有这个数据(数据所在的数组),没有那么就存储
if(gm == null){
// 8.3没有就创建
gm = [{
goodsId:this.goodsId,
num:1,
msg:this.getData(this.goodsId)
}]
}
else{
// 8.4把数组json变成对象类型,方便直接获取属性
gm = JSON.parse(gm);
var zhuangtai = 0;
// 8.5判断存入的数据是否在数组中有,有的话加数量,没有的话把这个数据放到数组中
for(var i = 0;i<gm.length;i++){
if(gm[i].goodsId == this.goodsId){
gm[i].num++;
zhuangtai = 1;
break;
}
}
// 8.6 表示数组中没有此数据,添加进去
if(zhuangtai == 0){
gm.push({
goodsId:this.goodsId,
num:1,
// 8.7 通过传入的goodsid在getData()方法中,如果传入的数据=对应数据的id,那么就把对应的数据拿过来
msg:this.getData(this.goodsId)
})
}
}
//9.以上这个if里面只是在判断操作获取到的数据,并没有存回去,所以最终操作完之后,需要将数据存到本地存储中
localStorage.setItem("goodsMsg",JSON.stringify(gm));
}
// 主要的作用是可以通过点击对应商品,获取商品id,然后遍历整个数据然后找到对应id所贮备的数据
// // 单独封装为了方便获取所有数据中,某个数据的功能
// // 根据传入的id获取
getData(id){
//遍历的时候,比较,符合,返回这个数据(判断是否有这个数据)
for(var i = 0;i<this.data.length;i++){
if(this.data[i].goodsId ==id){
return this.data[i];
}
}
//没有符合,返回空对象,保持数据格式一致
return {};
}
//
}
// 6.可以先创建实例对象查看
var gl = new GoodsList();
gl.init();
gl.addEvent();
</script>
</html>
购物车
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
img{width: 100px;height: 100px;}
</style>
</head>
<body>
<h2>这是购物车 <a href="商城商品展示.html">点击返回商城</a></h2>
<table border=1 width = 800px align = "center">
<thead>
<tr>
<th>图片</th>
<th>名字</th>
<th>单价</th>
<th>数量</th>
<th>总价</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</body>
<script type="text/javascript">
class Car{
// 1.构造函数
constructor(){
this.tBody = document.querySelector("tbody");
}
// 2.从本地存储中拿到数据,准备在购物车页面显示
getData(){
// 2.1 立即拿到数据
if(localStorage.getItem("goodsMsg")){
// 2.2把其变为json对象格式,方便于调用其中的属性
this.gm = JSON.parse(localStorage.getItem("goodsMsg"));
}
else{
this.gm = [];
}
//3.准备渲染页面
this.display();
}
display(){
// 3.1 准备一个空字符串
var str = "";
// 3.2把数据填入字符串中,准备放到页面上
for(var i=0;i<this.gm.length;i++){
str += `<tr index="${this.gm[i].goodsId}">
<td><img src="${this.gm[i].msg.img}" alt=""></td>
<td>${this.gm[i].msg.name}</td>
<td>${this.gm[i].msg.price}</td>
<td><input type="number" min="1" value="${this.gm[i].num}" class="number"></td>
<td>${ this.gm[i].msg.price * this.gm[i].num }</td>
<td class="delete">删除</td>
</tr>`;
}
// 3.3渲染
this.tBody.innerHTML = str;
}
// 事件绑定
addEvent(){
var that = this;
// 4.删除功能
// 4.1因为我们一开始在html中并没有删除,所以需要用到事件委托
this.tBody.onclick = function(eve){
var e = eve || window.event;
var tar = e.target || e.srcElement;
if(tar.className == "delete" ){
// 4.2先获取当前点击删除按钮的商品的id
that.id = tar.parentNode.getAttribute("index");
// 4.3删除对应DOM元素
tar.parentNode.remove();
// 4.5删除对应存储在本地的数据
that.changeData(function(i){
that.gm.splice(i,1);
});
}
}
// 5.总价跟着数量而改变
// 5.1首先也是通过事件委托拿到数量
this.tBody.oninput = function(eve){
var e = eve || window.event;
var tar = e.target || e.srcElement;
if(tar.className === "number"){
//5.2.获取要修改数量的商品的id
that.id = tar.parentNode.parentNode.getAttribute("index");
// 5.3.执行修改本地存储中数据的功能
that.changeData(function(i){
that.gm[i].num = tar.value;
});
// 5.4每次修改数量时,来计算总价
tar.parentNode.nextElementSibling.innerHTML = tar.value * tar.parentNode.previousElementSibling.innerHTML;
}
}
}
// 4.4通过点击获取的商品的id来找到本地存储中对应商品
changeData(cb){
// 根据点击的商品的id查找本地存储的数据中符合的商品数据
for(var i=0;i<this.gm.length;i++){
if(this.gm[i].goodsId === this.id){
cb(i);
break;
}
}
// 剔除掉之后,得再存回去,否则仅仅是在内存中修改,没有修改本地存储
localStorage.setItem("goodsMsg",JSON.stringify(this.gm));
}
}
// 4.先创建实例对象进行页面查看
var c = new Car();
c.getData();
c.addEvent();
</script>
</html>