Vue版购物车开发思路教程
日期:2018-04-30
来源:程序思维浏览:3682次
Vue是现在最流行的前端框架,电商是最热门的行业,购物车是电商的核心功能,那么如何开发一个扩展性强、易维护的购物车组件呢?下面就给大家介绍一下用Vue开发购物车的思路吧。
1、进入商品详情页面选择商品规格
选择颜色或尺码,输入购买数量,点击确定进入购物车。
放入购物车的字段如下:
商品的id:gid
商品名称:title
商品图片:img
商品数量:amount
商品运费:freight
商品价格:price
是否选中:checked(值true,false)
商品属性(规格):
[{"attrid":"1034","title":"颜色","param":[{"paramid":"1189","title":"蓝色"}]},{"attrid":"1037","title":"尺码","param":[{"paramid":"1192","title":"37"}]}]
2、vuex和localStorage的作用
Vuex的作用:将购物车的数据存储到vuex中实现组件传值和双向绑定。
localStorage的作用:解决vuex刷新页面数据丢失的问题,将vuex中的数据缓存起来。
如上面两张图所示购物车里还没有商品。
3、购物车组件页面源码
cart/index.vue
<!--模板-->
<template>
<div id="cart-index">
<div v-wechat-title="$route.meta.title"></div>
<div id="luck-page" class="luck-page">
<subHeader :navTitle=navTitle></subHeader>
<div id="cart-main" class="cart-main">
<div v-for="(item,index) in cartData" class="item-list">
<div class="select-area">
<label :class="{'check-mark':true,'active':item.checked}" @click="selectCart(''+item.gid+'')"></label>
</div>
<div class="items-wrap">
<div class="goods-image"><img :src="item.img" /></div>
<div class="del" @click="delCart(''+index+'')">删除</div>
<div class="goods-title">{{item.title}}</div>
<div class="goods-param"><span class="attr" v-for="attr in item.attrs">{{attr.title}}:<span class="param" v-for="param in attr.param">{{param.title}}</span></span></div>
<div class="price">¥{{item.price}}</div>
<div class="itemsCount">
<div class="num-wrap">
<div class="minus active" @click="minus(''+item.gid+'',''+item.amount+'',''+item.checked+'')">-</div>
<div class="input-num"><input type="tel" class="amount" name="amount" v-model="item.amount" @keyup="checkAmount()" @blur="changeAmount(''+item.gid+'')" ></div>
<div class="plus" @click="plus(''+item.gid+'',''+item.amount+'',''+item.checked+'')">+</div>
</div>
</div>
</div>
</div>
</div>
<div class="sett-nav">
<div class="sett-left">
<div class="choose" id="all-check">
<label @click="allSelectCart()" >
<div :class="{'check-mark':true,'active':bAllChecked}"></div>
<div class="check-text">全选</div>
</label>
</div>
<div class="total">合计: <span>¥<span id="total">{{priceTotal}}</span></span></div>
</div>
<button type="button" @click="goOrder()" :class="{'sett-right':true,'disable':!bAllChecked}">去结算</button>
</div>
</div>
</div>
</template>
<!--行为-->
<script>
import subHeader from '../../common/page/sub-header'
export default {
name: 'cart-index',
data:function(){
return {
cartData:this.$store.state.cartData.length>0?this.$store.state.cartData:localStorage.cart!=undefined?JSON.parse(localStorage.cart):[],
priceTotal:this.$store.state.priceTotal>0?this.$store.state.priceTotal:localStorage.priceTotal!=undefined?localStorage.priceTotal:0,
bChecked:true,
bAllChecked:true,
navTitle:"购物车"
}
},
components:{
subHeader
},
methods:{
back(){
this.$router.go(-1);
},
//点击选择
selectCart(pGid){
if(this.bChecked){
this.bChecked=false;
}else{
this.bChecked=true;
}
this.$store.commit("checkedCartData", {gid: pGid, checked: this.bChecked});
this.priceTotal=this.$store.state.priceTotal;
this.setAllChecked();
},
//点击全择
allSelectCart(){
if(this.cartData.length>0) {
if (this.bAllChecked == true) {
this.bAllChecked = false;
} else {
this.bAllChecked = true;
}
this.$store.commit("allCheckedCartData", this.bAllChecked);
this.priceTotal = this.$store.state.priceTotal;
}
},
//点击减号
minus(pGid,pAmount,pChecked){
if(pChecked=='true') {
let iAmount = parseInt(pAmount);
if (iAmount <= 1) {
iAmount = 1;
} else {
iAmount -= 1;
}
this.$store.commit("changeAmount", {gid: pGid, amount: iAmount});
this.priceTotal = this.$store.state.priceTotal;
}
},
//点击加号
plus(pGid,pAmount,pChecked){
if(pChecked=='true') {
let iAmount = parseInt(pAmount);
iAmount += 1;
this.$store.commit("changeAmount", {gid: pGid, amount: iAmount});
this.priceTotal = this.$store.state.priceTotal;
}
},
//检测输入的数量是否规范
checkAmount(){
for(var key in this.cartData){
if(isNaN(this.cartData[key].amount)){
this.cartData[key].amount=this.cartData[key].amount.replace(/[a-zA-Z]|[\u4e00-\u9fa5]/g,'')
this.bSubmitAmount=false;
break;
}else if(this.cartData[key].amount<=0){
this.cartData[key].amount=1;
break;
} else{
this.bSubmitAmount=true;
}
}
},
//修改数量
changeAmount(pGid){
if(this.bSubmitAmount) {
for(let key in this.cartData){
if(this.cartData[key].gid==pGid){
if(this.cartData[key].checked==true){
this.$store.commit("changeAmount");
this.priceTotal = this.$store.state.priceTotal;
}
break;
}
}
}
},
//删除宝贝
delCart(pIndex){
this.$store.commit("delCart", {index: pIndex});
this.priceTotal = this.$store.state.priceTotal;
this.setAllChecked();
},
setAllChecked(){
if(this.priceTotal>0) {
this.bAllChecked = true;
}else{
this.bAllChecked = false;
}
},
goOrder(){
if(this.priceTotal>0) {
this.$router.push({path:this.config.path+ 'order/index'});
}
}
},
mounted:function(){
if(this.priceTotal>0){
this.bAllChecked=true;
}else{
this.bAllChecked=false;
}
},
created:function(){
this.bSubmitAmount=true;
this.cartData=this.$store.state.cartData.length>0?this.$store.state.cartData:localStorage.cart!=undefined?JSON.parse(localStorage.cart):[]
}
}
</script>
<!--样式-->
<style scoped>
.cart-main{width:100%;margin-top:2.5rem;padding-bottom:2.5rem;background:#FFFFFF;}
.cart-main .item-list{width:100%;height:6rem;background:#FFFFFF;border-bottom:#EFEFEF solid 2px;overflow:hidden;}
.cart-main .select-area{width:10%;height:100%;float:left;position:relative;}
.cart-main .select-area .check-mark{width:0.8rem;height:0.8rem;border:#EFEFEF solid 1px;border-radius:100%;position:absolute;z-index:1;top:43%;left:15%;}
.cart-main .select-area .check-mark input{opacity:0;width:100%;height:100%;}
.cart-main .select-area .check-mark.active{background-image:url("../../../assets/images/home/cart/checkmark.png");background-size:100%;background-repeat:no-repeat;background-position:center;border:none 0px;}
.cart-main .items-wrap{width:90%;height:100%;float:left;position:relative;}
.cart-main .items-wrap .goods-image{width:3rem;height:3rem;position:absolute;z-index:1;left:0px;top:25%;}
.cart-main .items-wrap .goods-image img{width:100%;}
.cart-main .items-wrap .goods-title{width: 70%;height: 1.5rem;font-size: 0.6rem; position: absolute;z-index: 1;left:25%;top: 10%;overflow: hidden;line-height: 0.8rem;text-align:left;}
.cart-main .items-wrap .goods-param{width: 70%;height: auto;font-size: 0.6rem; position: absolute;z-index: 1;left:25%;top: 38%;overflow: hidden;text-align:left;white-space:nowrap;text-overflow:ellipsis;color:#B5B5B5;}
.cart-main .items-wrap .goods-param .attr{margin-right:10px;}
.cart-main .items-wrap .goods-param .param{margin-right:5px;}
.cart-main .items-wrap .price{width:30%;height:auto;position:absolute;z-index:1;left:25%;top:65%;color:#CC0004;font-size:0.7rem;}
.cart-main .items-wrap .itemsCount{width:30%;height:auto;position:absolute;z-index:1;left:65%;top:65%;}
.cart-main .items-wrap .itemsCount .num-wrap{width:5rem;height:1.2rem;border:solid 1px #000000;border-radius:3px;position:absolute;z-index:1;right:5%;top:0%;overflow:hidden;}
.cart-main .items-wrap .itemsCount .num-wrap .minus{width:1.5rem;height:0.8rem;border-right:#B5B5B5 solid 1px;margin-top:4%;color:#B5B5B5;text-align:center;line-height:0.8rem;float:left;}
.cart-main .items-wrap .itemsCount .num-wrap .minus.active{color:#000000;border-right:#000000 solid 1px;}
.cart-main .items-wrap .itemsCount .num-wrap .plus{width:1.5rem;height:0.8rem;border-left:#000000 solid 1px;margin-top:4%;color:#000000;text-align:center;line-height:0.8rem;float:left;}
.cart-main .items-wrap .itemsCount .input-num{width:1.9rem;height:auto;float:left;margin-top:-0.2rem;}
.cart-main .items-wrap .itemsCount .input-num .amount{width:100%;font-size:0.7rem;border:none 0px;outline:none;-webkit-appearance:none;text-align:center;}
.cart-main .items-wrap .del{width:auto;height:auto;position:absolute;z-index:1;left:1rem;top:83%;font-size: 0.6rem;color:#B5B5B5;}
.sett-nav{width:100%;height:2.5rem;position:fixed;z-index:5;bottom:0px;border-top:solid #EFEFEF 1px;background:#FFFFFF;}
.sett-left{width:70%;height:100%;position:relative;float:left;}
.sett-nav .sett-left .choose{width:5rem;height:auto;position:absolute;z-index:5;left:5%;top:30%;}
.sett-nav .sett-left .choose .check-mark{width:0.8rem;height:0.8rem;border:#EFEFEF solid 1px;border-radius:100%;}
.sett-nav .sett-left .choose .check-mark.active{background-image:url("../../../assets/images/home/cart/checkmark.png");background-size:100%;background-repeat:no-repeat;background-position:center;border:none 0px;}
.sett-nav .sett-left .choose .check-text{width:2rem;height:auto;position:absolute;z-index:5;left:25%;top:15%;font-size:0.6rem;}
.sett-nav .sett-left .total{width:auto;height:auto;position:absolute;right:4%;top:33%;z-index:5;font-size:0.6rem;}
.sett-nav .sett-left .total span{color:#CC0004}
.sett-nav .sett-right{width:30%;height:100%;background:#CC0004;text-align:center;line-height:2.5rem;float:left;color:#FFFFFF;font-size:0.8rem;border-radius: 0px;}
.sett-nav .sett-right.disable{background:#BFBFBF;}
</style>
4、添加购物车
当我点击加入购物车后将数据存储到vuex和localStorage中,
代码如下:
main.js里面的代码
import state from './store/state.js'
import mutations from './store/mutations.js'
let store=new Vuex.Store({
state,
mutations
});
state.js里面的代码
export default {
//这里设置初始值的作用是:当浏览器关闭,再次打开时获取缓存数据。
//购物车的json数据,如果localStorage.cart里面有数据就读取缓存中的数据,否则设置初始值为:[]
cartData:localStorage.cart!=undefined?JSON.parse(localStorage.cart):[],
//缓存中有商品总价就读取,否则设置初始值为:0
priceTotal:localStorage.priceTotal!=undefined?localStorage.priceTotal:0,
//缓存中有运费就读取,否则设置初始值为:0
freightTotal:localStorage.freightTotal!=undefined?localStorage.freightTotal:0
}
添加购物车的方法写在mutations.js里面
export default {
addCartData(state,data) {//添加购物车
state.cartData=localStorage.cart!=undefined?JSON.parse(localStorage.cart):[];
state.priceTotal=parseFloat(localStorage.priceTotal).toFixed(2);
state.freightTotal=parseFloat(localStorage.freightTotal).toFixed(2);
if(data.gid!='' && data.gid>0) {
let existGid=false,priceTotal=0,freightTotal=0,aFreight=[];
for(let i=0;i<state.cartData.length;i++) {
//如果购物车商品有重复修改数量和价格
if (data.gid == state.cartData[i].gid) {
state.cartData[i].amount++;
state.cartData[i].price+=state.cartData[i].price;
state.cartData[i].attrs=data.attrs;
existGid=true;
break;
}
}
//增加购物车商品
if(existGid==false){
state.cartData.push(data);
}
//计算总价
for(let i=0;i<state.cartData.length;i++) {
priceTotal += (state.cartData[i].price * state.cartData[i].amount);
aFreight.push(state.cartData[i].freight);
}
freightTotal=Math.max.apply(null,aFreight);
//console.log(JSON.stringify(state.cartData))
state.priceTotal=priceTotal.toFixed(2);
state.freightTotal=freightTotal.toFixed(2)
localStorage.cart=JSON.stringify(state.cartData);
localStorage.priceTotal=priceTotal.toFixed(2);
localStorage.freightTotal=freightTotal.toFixed(2);
}
}
}
这样购物车里就增加了一个商品,如果是相同的商品数量加1,更改价格,如果是不同的商品购物车里会出现新的商品。如图:
5、更改数量
进入购物车页面修改商品的数量。
细节注意:如果输入的数量是字符或是汉字需自动消除掉,如果输入的数量是0,自动变为1。
更改数量的代码写在mutations.js里面
代码如下:
changeAmount(state,data){//更改数量
let priceTotal=0;
if(data) {
for (let i = 0; i < state.cartData.length; i++) {
if (state.cartData[i].gid == data.gid) {
state.cartData[i].amount = data.amount;
break;
}
}
}
for(let i=0;i<state.cartData.length;i++) {
priceTotal += (state.cartData[i].price * state.cartData[i].amount);
}
state.priceTotal=priceTotal.toFixed(2);
localStorage.priceTotal=priceTotal.toFixed(2);
localStorage.cart=JSON.stringify(state.cartData);
}
6、删除购物车里的商品
删除购物车的代码写在mutations.js里面
代码如下:
delCart(state,data){//删除购物车里的宝贝
let priceTotal=0,freightTotal=0,aFreight=[];
state.cartData.splice(data.index,1);
for(let i=0;i<state.cartData.length;i++) {
priceTotal += (state.cartData[i].price * state.cartData[i].amount);
aFreight.push(state.cartData[i].freight);
}
freightTotal=Math.max.apply(null,aFreight);
state.priceTotal=priceTotal.toFixed(2);
state.freightTotal=freightTotal.toFixed(2);
localStorage.priceTotal=priceTotal.toFixed(2);
localStorage.cart=JSON.stringify(state.cartData);
localStorage.freightTotal=freightTotal.toFixed(2);
}
7、勾选购物车里面的商品
如图:
细节注意:未勾选时,合计总价要减去未选中是商品价格,当全部未选中时,全选要自动设置成未勾选状态,去结算按钮不能点击,并且要置灰,未选中的商品不能点击+-号,且输入数量不能计算价格。
如图:
勾选的代码写在mutations.js里面
代码如下:
勾选购物车里面的商品
checkedCartData(state,data){
let priceTotal=0;
for(let i=0;i<state.cartData.length;i++){
if(data.gid==state.cartData[i].gid){
state.cartData[i].checked=data.checked;
break;
}
}
for(let i=0;i<state.cartData.length;i++){
if(state.cartData[i].checked==true) {
priceTotal += (state.cartData[i].price * state.cartData[i].amount);
}
}
state.priceTotal=priceTotal.toFixed(2);
localStorage.cart=JSON.stringify(state.cartData);
localStorage.priceTotal=priceTotal.toFixed(2);
}
8、全选与反选购物车里面的商品
全选如图:
反选如图:
细节注意:当全选按钮未选中时,合计总价为0,去结算按钮不能点击,并且要置灰,未选中的商品不能点击+-号,且输入数量不能计算价格。
最后存储到vuex中的 cartData json数据为:
[{"gid":"747503321","title":"波司登加绒加厚牛仔裤女秋冬2016新款个性百搭外穿宽松复古小脚裤","amount":10,"price":158,"img":"http://vueshop.glbuys.com/uploadfiles/1484288933.jpg","checked":true,"freight":0,"attrs":[{"attrid":"1011","title":"颜色","param":[{"paramid":"917","title":"红色"}]},{"attrid":"1012","title":"腰围","param":[{"paramid":"920","title":"12cm"}]}]},{"gid":"981541541","title":"欧美尖头蝴蝶结拖鞋女夏外穿2018新款绸缎面细跟凉拖半拖鞋穆勒鞋","amount":3,"price":1020,"img":"http://vueshop.glbuys.com/uploadfiles/1524556315.jpg","checked":true,"freight":20,"attrs":[{"attrid":"1034","title":"颜色","param":[{"paramid":"1189","title":"蓝色"}]},{"attrid":"1037","title":"尺码","param":[{"paramid":"1192","title":"37"}]}]},{"gid":"767430600","title":"雪兰黛2018春季新款高跟鞋尖头细跟性感鞋子女韩版透气纱网女单鞋 ","amount":1,"price":280,"img":"http://vueshop.glbuys.com/uploadfiles/1524556026.jpg","checked":true,"freight":10,"attrs":[{"attrid":"1034","title":"颜色","param":[{"paramid":"1170","title":"黑白"}]},{"attrid":"1037","title":"尺码","param":[{"paramid":"1174","title":"36"}]}]}]
- 上一篇:SVG动画、CSS3动画常用知识点全解析
- 下一篇:什么是VUE?VUE与JS的对比
精品好课