HTML:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>购物车示例</title> <link rel="stylesheet" href="index.css"> </head> <body> <div id="app" v-cloak> <template v-if="allListNum"> <table> <thead> <tr> <th> <input type="checkbox" v-model="checkAll">全选 </th> <th>商品名称</th> <th>商品单价</th> <th>购买数量</th> <th>操作</th> </tr> </thead> <tbody> <template v-for="(item,index) in list"> <tr v-if="item.content.length"> <td colspan="5">{{item.name}}</td> </tr> <tr v-for="(small,smallIndex) in item.content"> <!-- <td>{{index+1}}</td> --> <td><input type="checkbox" :checked="small.check" @click="isAll(index,smallIndex)"> {{small.check}}</td> <td>{{small.name}}</td> <td>{{small.price}}</td> <td> <button @click="handleReduce(index,smallIndex)" :display="small.count===1">-</button> {{small.count}} <button @click="handleAdd(index,smallIndex)">+</button> </td> <td> <button @click="handleRemove(index,smallIndex)">移除</button> </td> </tr> </template> </tbody> </table> <div>总价:¥{{totalPrice}}</div> </template> <div v-else> 购物车为空 </div> </div> <script src="../../vue.js"></script> <script src="./index.js"></script> </body> </html>
JS:
var app=new Vue({ el:'#app', data:{ list:[ { name:'电子产品', content:[ { id:1, name:'iPhone 7', price:6288, count:1, check:false },{ id:2, name:'iPad Pro', price:5888, count:1, check:false },{ id:3, name:'MacBook Pro', price:21488, count:1, check:false } ] },{ name:'图书', content:[ { id:1, name:'《小王子》', price:10000000000, count:1, check:false },{ id:2, name:'《失控》', price:100, count:1, check:false },{ id:3, name:"《目送》", price:40, count:1, check:false },{ id:4, name:'《爱与孤独》', price:10, count:1, check:false } ] } ], checkAll:false, smallHand:false }, computed:{ totalPrice:function(){ var arr=[]; for(var i=0;i<this.list.length;i++){ arr=arr.concat(this.list[i]['content']); } this.newList=arr.filter(function(item){ if(item.check){ return item; } }); var total=0; for(var i=0;i<this.newList.length;i++){ var item=this.newList[i]; total+=item.price*item.count; } return total.toString().replace(/B(?=(d{3})+$)/g,',');//匹配后面已3个数字结尾的非单词边界,换成“,” /* replace: 用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串 B :匹配非单词边界 (red|blue|green):查找任何指定的选项 ?=n :匹配任何其后紧接指定字符串n的字符串(n量词) 提供后面的n找? d :查找数字 n{X}:匹配包含X个n的序列字符串 d{3}:匹配含有3个数字的字符串 n$ :匹配任何结尾为n的字符串 n+ :匹配任何包含至少一个n的字符串 (d{3})+$ :匹配至少一个已含有3个数字字符串结尾的字符 */ }, allListNum:function(){ var allNum=0; for(var i=0;i<this.list.length;i++){ var item=this.list[i]['content']; for(var j=0;j<item.length;j++){ allNum++; } } return allNum; } }, methods:{ handleReduce:function(index,smallIndex){ console.log(index); console.log(smallIndex); if(this.list[index]['content'][smallIndex].count===1) return; this.list[index]['content'][smallIndex].count--; }, handleAdd:function(index,smallIndex){ this.list[index]['content'][smallIndex].count++; }, handleRemove:function(index,smallIndex){ this.list[index]['content'].splice(smallIndex,1); var num=0; for(var i=0;i<this.list.length;i++){ var item=this.list[i]['content']; for(var j=0;j<item.length;j++){ if(item[j].check){ num++; }else{ num--; } } } if(num==this.allListNum){ this.checkAll=true; }else{ this.checkAll=false; } }, isAll:function(index,smallIndex){ console.log(this.list[index]['content'][smallIndex].check); var indexItem=this.list[index]['content'][smallIndex]; indexItem.check=!indexItem.check; var num=0; for(var i=0;i<this.list.length;i++){ var item=this.list[i]['content']; for(var j=0;j<item.length;j++){ if(item[j].check){ num++; }else{ num--; } } } console.log(num);////(选中了最后一个)3-全部勾选-勾选全选 (之前全部勾选,取消了任意一个勾选) 1-取消全选的勾选 // if(num==7||(num==5&&indexItem.check==false)){ 这里的值不能写死,太笨了 if(num==this.allListNum||(num==(this.allListNum-2)&&indexItem.check==false)){ this.checkAll=indexItem.check; this.smallHand=true; } } }, watch:{ checkAll:function(){ if(this.smallHand){ }else{ for(var i=0;i<this.list.length;i++){ var list=this.list; for(var j=0;j<list[i]['content'].length;j++){ this.list[i]['content'][j]['check']=this.checkAll; } } } this.smallHand=false; } } })
CSS:
[v-cloak] { display: none; } table { border: 1px solid #e9e9e9; border-collapse: collapse; border-spacing: 0; empty-cells: show; } table th, table td { padding: 8px 16px; border: 1px solid #e9e9e9; text-align: left; } table th { background: #f7f7f7; color: #5c6b77; font-weight: 600; white-space: nowrap; }
总结:相比前一个购物车,这个购物车可实现物品分类,数据又多了一层嵌套。