最近后端的同事要我写一个购物车,一开始我用jQuery写,但写着写着发现逻辑太混乱了,写不下去。最后花了五分钟找了个demo丢给了他。后来我不甘心,毕竟水平菜还不求上进就完蛋了。因此我想着用vue来实现一个。javascript
原本想看看别人的代码,但搜索了下github发现,能找到的购物车都是两级分类的。而京东、淘宝之流都是三级分类的: 1. 全选 2. 店铺全选 3. 商品选中
这样的貌似才有实用价值css
<div id="cart"> <section class="cartMain"> <div class="cartMain_hd"> <ul class="order_lists cartTop"> <li class="list_chk"> <!--全部商品全选--> <input type="checkbox" id="all" class="whole_check"> <label for="all" :class="fetchData.status?'mark':''" @click="cartchoose()"></label> 全选 </li> <li class="list_con">商品信息</li> <li class="list_info">商品参数</li> <li class="list_price">单价</li> <li class="list_amount">数量</li> <li class="list_sum">金额</li> <li class="list_op">操做</li> </ul> </div> <div class="cartBox" v-for="item in fetchData.list" key="index"> <div class="shop_info"> <div class="all_check"> <input type="checkbox" id="shop_a" class="shopChoice"> <label for="shop_a" class="shop" :class="item.check?'mark':''" @click="shopchoose(item)"></label> </div> <div class="shop_name"> 店铺:<a href="javascript:;">{{item.shop_name}}</a> </div> </div> <div class="order_content"> <ul class="order_lists" v-for="pro in item.products"> <li class="list_chk"> <input type="checkbox" id="checkbox_2" class="son_check"> <label for="checkbox_2" :class="pro.checked?'mark':''" @click="choose(item,pro)"></label> </li> <li class="list_con"> <div class="list_img"><a href="javascript:;"><img :src="pro.img" alt=""></a></div> <div class="list_text"><a href="javascript:;">{{pro.text}}</a> <span class="list_custom">定制</span> </div> </li> <li class="list_info"> <p>规格:默认</p> <p>尺寸:16*16*3(cm)</p> </li> <li class="list_price"> <p class="price">¥{{pro.price}}</p> <div class="charge"> <p>更多促销</p> <div class="chargebox"> 测试 </div> </div> </li> <li class="list_amount"> <div class="amount_box"> <a href="javascript:;" class="reduce reSty" @click="reduce(pro)">-</a> <input type="text" v-model="pro.num" class="sum"> <a href="javascript:;" class="plus" @click="add(pro)">+</a> </div> </li> <li class="list_sum"> <p class="sum_price">¥{{pro.sum}}</p> </li> <li class="list_op"> <p class="collect"><a href="javascript:;" class="colBtn">收藏商品</a></p> <p class="del"><a href="javascript:;" class="delBtn">移除商品</a></p> <p class="custom"><a href="javascript:;" class="cusBtn">定制商品</a></p> <div class="custombox"> 测试 </div> </li> </ul> </div> </div> <!--底部--> <div class="bar-wrapper"> <div class="bar-right"> <div class="piece">已选商品<strong class="piece_num">{{this.fetchData.allnum}}</strong>件</div> <div class="totalMoney">共计: <strong class="total_text">¥{{this.fetchData.allsum}}</strong></div> <div class="calBtn"><a href="javascript:;">结算</a></div> </div> </div> </section> <section class="model_bg"></section> <section class="my_model"> <p class="title">删除宝贝<span class="closeModel">X</span></p> <p>您确认要删除该宝贝吗?</p> <div class="opBtn"><a href="javascript:;" class="dialog-sure">肯定</a><a href="javascript:;" class="dialog-close">关闭</a></div> </section> </div>
大概长这个样子,很普通的一个购物车页面,另外html和css部分不是我写的,是下载的jQuery购物车的demo里的代码,这样比较省事情。html
1.三级选中按钮的实现
2.每件商品总价的变更
3.商品总件数、商品总计价格的变更
4.输入商品数量致使2,3的变更(未实现)vue
data(){ return{ fetchData:{ list:[ { shop_id:1, shop_name:'搜猎人艺术生活', products:[ { pro_id:101, text:'洗面奶洗面奶洗面奶洗面奶洗面奶洗面奶洗面奶洗面奶', price:480, num:1, img:'./images/1.png', sum:480, checked:false//商品选中状态 }, { pro_id:102, text:'花露水花露水花露水花露水花露水花露水花露水花露水', price:680, num:1, img:'./images/2.png', sum:680, checked:false }, { pro_id:103, text:'燕麦片燕麦片燕麦片燕麦片燕麦片燕麦片燕麦片燕麦片', price:380, num:1, img:'./images/3.png', sum:380, checked:false } ], check:false,//店铺选中状态 choose:0,//商品选中个数 }, { shop_id:2, shop_name:'卷卷旗舰店', products:[ { pro_id:201, text:'剃须刀剃须刀剃须刀剃须刀剃须刀剃须刀剃须刀剃须刀', price:580, num:1, img:'./images/4.png', sum:580, checked:false }, { pro_id:202, text:'卫生纸卫生纸卫生纸卫生纸卫生纸卫生纸卫生纸卫生纸', price:780, num:1, img:'./images/5.png', sum:780, checked:false } ], check:false, choose:0, }, { shop_id:3, shop_name:'瓜皮的神秘商店', products:[ { pro_id:301, text:'眼镜片眼镜片眼镜片眼镜片眼镜片眼镜片眼镜片眼镜片', price:180, num:1, img:'./images/6.png', sum:180, checked:false }, { pro_id:302, text:'凑数的凑数的凑数的凑数的凑数的凑数的凑数的凑数的', price:280, num:1, img:'./images/7.png', sum:280, checked:false } ], check:false, choose:0, } ], status:false,//全选选中状态 allchoose:0,//店铺选中个数 allsum:0,//总计价格 allnum:0//总计数量 } } },
意义不明的部分写了注释,其余数据一目了然java
单个商品的选中按钮很容易实现,通常是添加一个点击方法,值取反。但在购物车中这样的方法是不行的,单个商品的选中以及取消所执行的逻辑有部分不一样,因此我选择将其拆分。git
choosetrue(item,pro){ pro.checked=true//将商品选中状态改成true ++item.choose===item.products.length?item.check=true:''//这里执行了两部,选中商品数量先+1,再与该店铺商品数量比较,若是相等就更改店铺选中状态为true item.check?++this.fetchData.allchoose===this.fetchData.list.length?this.fetchData.status=true:this.fetchData.status=false:''//若是店铺选中状态改成true,选中店铺数量先+1,再与店铺数量比较,若是相等就更改全选选中状态为true }, choosefalse(item,pro){ pro.checked=false//将商品选中状态改成false --item.choose//选中商品数量-1 if(item.check){//若是店铺是被选中的,更改店铺选中状态 item.check=false --this.fetchData.allchoose//而且选中店铺数量-1 } this.fetchData.status=false//不管以前全选的状态,将其改成false就行 }, choose(item,pro){ !pro.checked?this.choosetrue(item,pro):this.choosefalse(item,pro) },//这里是绑定到html上的方法,取反是因为你在触发方法的时候取的是以前的状态
相信有的人看了代码仍是以为能把三个函数写在一块儿,其实我以前就是这么干的,而后就悲剧了,多是我功底不够。先无论这些。如今分析下店铺全选的逻辑:github
选中以后,店铺下的全部商品选中,而且判断全选按钮是否要选中后端
取消选中,店铺下的全部商品取消选中app
这是基本逻辑,但若是照这个思路写,用循环将商品状态更改,很轻松,可是仍是须要判断是否要选中全选按钮。咱们换个思路吧,由于我发现“判断是否要选中全选按钮”已经在以前写过了。店铺选中按钮的前半部分逻辑其实就是choosetrue函数执行了必定的次数,我是这样写的:函数
shoptrue(item){ item.products.forEach((pro)=>{ pro.checked===false?this.choosetrue(item,pro):'' }) },//循环店铺中的商品,先筛选出目前没选中的商品,给它执行choosetrue函数 shopfalse(item){ item.products.forEach((pro)=>{ pro.checked===true?this.choosefalse(item,pro):'' }) },//循环店铺中的商品,先筛选出目前被选中的商品,给它执行choosefalse函数 shopchoose(item){ !item.check?this.shoptrue(item):this.shopfalse(item) },
刚才分开写的好处就出现啦,至于为何要筛选一下,这和以后计算商品总价有关系(若是只是写多选按钮的逻辑,有人会图方便不筛选,好比一小时以前的我)
cartchoose(){ this.fetchData.status=!this.fetchData.status//取反改变状态 this.fetchData.status?this.fetchData.list.forEach((item)=>this.shoptrue(item)):this.fetchData.list.forEach((item)=>this.shopfalse(item)) },//根据取反后的状态进行相应的店铺按钮操做
有人可能发现为何全选不进行筛选,实际上是不须要筛选。以前选中的店铺按钮下的商品状态必然所有是true,只是空跑了一遍,总结起来的逻辑是:没选中的店铺改变状态->没选中的商品改变状态
add(pro){ pro.num++//商品数量+1 pro.sum+=pro.price//商品总价变更 }, reduce(pro){ if(pro.num===1){ pro.num//当商品数量=1,不变 }else{ pro.num--//不然-1 pro.sum-=pro.price//商品总价变更 } }
这里的逻辑比较简单,不细说。
接下来就是商品总计价格的变更,这里又要分析一下:首先,选中的商品才会影响总计价格的变更,那咱们只须要将逻辑写着choosetrue函数中就行,而不须要去一遍一遍循环选中商品的总价格去计算总计价格,稍微调整下。
choosetrue(item,pro){ pro.checked=true ++item.choose===item.products.length?item.check=true:'' item.check?++this.fetchData.allchoose===this.fetchData.list.length?this.fetchData.status=true:this.fetchData.status=false:'' this.fetchData.allsum+=pro.sum//当触发商品选中按钮,将商品总价格添加到总计价格 }, choosefalse(item,pro){ pro.checked=false --item.choose if(item.check){ item.check=false --this.fetchData.allchoose } this.fetchData.status=false this.fetchData.allsum-=pro.sum//当触发商品取消按钮,将商品总价格从总计价格删去 }, add(pro){ pro.num++ pro.sum+=pro.price pro.checked?this.fetchData.allsum+=pro.price:this.fetchData.allsum//这里判断下商品的状态决定是否是要改变总计价格 }, reduce(pro){ if(pro.num===1){ pro.num }else{ pro.num-- pro.sum-=pro.price pro.checked?this.fetchData.allsum-=pro.price:this.fetchData.allsum//同上 } }
商品数量的计算,这个淘宝和京东对数量的计算不一样,淘宝是商品种类的数量,京东是商品总件数量,逻辑也较简单,跟商品价格后面相应添加就行。
当手动输入商品数量时,价格随之变更,我思考了半天只想到数据监测,但数据嵌套太深了,若是监测fetchData,监测函数会屡次无心义触发,监测键盘也不现实,最好的办法是监测num这个数据,但我没继续实验,对watch用的不太熟。有小伙伴有实现方法麻烦告知
以前全部未完成部分已经解决,小伙伴们能够去github看源码。主要包括(商品数量计算,监控输入数字引发价格变更,输入数字的各类限制,避免有人填写负数和小数之类的)
有bug麻烦告知一声,谢谢