准备工作
环境
这里我们使用Bootstrap来简单的布局,并引入vue.js核心文件:
<link rel="stylesheet" type="text/css" href="../../Bootstrap/bootstrap-3.3.7-dist/css/bootstrap.css"/>
<script src="../../jquery_qqchat/js/jquery-3.4.1.js" type="text/javascript" charset="utf-8"></script>
<script src="../../Bootstrap/bootstrap-3.3.7-dist/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
注:Bootstrap引入顺序,先引入Bootstrap核心css文件,由于Bootstrap依赖于jQuery,因此,在引入Bootstrap核心js文件时,需先引入jQuery核心文件。
手动初始化数据
模拟一个购物车,我们需要一些订单数据,我们可以手动定义一个json数组来进行模拟:
let vue=new Vue({
el:"#app",
data:{
goodsArr:[
{id:0,name:"小米10",img:"img/5.png",price:4000,num:1},
{id:1,name:"Redmi K30",img:"img/8.png",price:1700,num:1},
{id:2,name:"Redmi K30 5G",img:"img/7.png",price:2000,num:1},
{id:3,name:"小米CC9 Pro",img:"img/2.png",price:2600,num:1},
{id:4,name:"Redmi 8",img:"img/1.png",price:700,num:1}
],
}
});
计算属性
需要计算购物车中的总金额,我们可以在methods里面写方法,也可以在computed里面写属性,两者的不同之处在于:所谓计算属性就可以看作是一个属性,使用时直接写属性名称,而方法在使用时,需要写的是:方法名()
computed:{
sum2:function(){
let money=0;
for(let item of this.goodsArr){
money+=item.price*item.num;
}
return money;
}
},
方法
那么说到方法,我们写个例子吧,比如我们需要在每一条记录上要计算出小计,即商品的单价*数量,可以写一个方法。此外,通常来说,购物车中也可以移除一条订单,因此我们也可以定义一个移除的方法,当点击移除按钮时,需要传入一个商品的id,用于标识用户要移除的是哪一个商品,然后根据商品的id来进行删除。
methods:{
sum1(price,num){
return price*num;
},
remove(id){
if(confirm("确定要移除该商品吗?")){
for(let i=0;i<this.goodsArr.length;i++){
if(id==this.goodsArr[i].id){
this.goodsArr.splice(i,1);
}
}
}
}
}
使用表格布局
<div id="app">
<div class="container">
<div class="table-responsive">
<table class="table table-hover " border="0" cellspacing="0" cellpadding="0">
<thead align="center">
<th>序号</th>
<th>商品名称</th>
<th>图片</th>
<th>单价(元)</th>
<th>总价(元)</th>
<th>数量</th>
<th>操作</th>
</thead>
<tr v-for="(good,index) in goodsArr">
<td>{{index+1}}</td>
<td>{{good.name}}</td>
<td><img :src="good.img" style="width: 70px;height: 70px;"></td>
<td>{{good.price}}</td>
<td>
{{sum1(good.price,good.num)}}
</td>
<td>
<div class="input-group">
<button :disabled="good.num<=1" class="btn-info input-group-addon" @click="good.num--">-</button>
<input type="text" :value="good.num" size="2" readonly style="border-width:0px;background:#F5F5F5;width:25px;height: 28px;" />
<button :disabled="good.num>=10" class="btn-info input-group-addon" @click="good.num++">+</button>
</div>
</td>
<td><a class="btn btn-danger" href="#" @click.prevent="remove(good.id)">移除</a></td>
</tr>
<tr align="center">
<td colspan="7">合计:{{sum2}} 元</td>
</tr>
</table>
</div>
</div>
</div>
</body>
注:我们自定义这样一个需求,每件商品的购买数量不得超过10,最低的购买数量不得少于1,我们可以使用 :disabled 来绑定,当数量大于10时,禁用按钮,当数量小于1时,也禁用按钮。此外,我们可以看到,移除我们使用的是一个超链接,我们只是使用了boostrap的样式看起来像按钮,但并非是一个button,那么,就会存在这样一个问题:当我们点击了之后,如果有连接地址,其实是会跳转的,我们事宜使用 @click.prevent来阻止其跳转。
效果图如下:
优化:在显示金额的地方,我们希望显示的格式为金额,如4000,应显示为:¥4000.00,我们可以手动写一个方法,只需在显示的地方调用此方法即可,具体如下:
showMoney(money){
return "¥"+money.toFixed(2);//保留数值的2位小数点
}
可以看到这个方法非常第简单。
优化功能
- 需求一:实现批量删除功能
- 需求二:清空购物车
批量删除
思路:我们可以在操作列添加一个复选框,在表格的底部添加一个批量删除按钮,当点击了批量删除按钮时,按钮的名称变为取消,在旁边新增一个确定按钮,并且在把表头的操作改为全选,把移除按钮隐藏,复选框显示。当点击确定按钮时,需要把勾选的对应的商品删除。
- 定义变量标识,用于判断是显示移除按钮还是显示复选框
isBatchDel:false,
btnValue:"批量删除"
2.在相应的标签上使用v-show指令
<label v-show="isBatchDel">全选<input type="checkbox" /></label>
<span v-show="!isBatchDel">操作</span>
<input v-show="isBatchDel" type="checkbox" name="" value="" />
<a v-show="!isBatchDel" class="btn btn-danger" href="#" @click.prevent="remove(good.id)">移除</a>
<button class="btn btn-danger" @click="batchDelClick()">{{btnValue}}</button>
<button v-show="isBatchDel" class="btn btn-danger">确定</button>
3.编写方法,改变isBatchDel和btnValue的值
batchDelClick(){
if(this.isBatchDel){
this.isBatchDel=false;
this.btnValue="批量删除";
}else{
this.isBatchDel=true;
this.btnValue="取消";
}
}
使用如上代码,我们就可以实现在移除和批量删除之间进行切换。
以上只是实现了一个界面的交互,并未实现功能,如当点击全选按钮时,下面所有的商品都应该被勾选下面继续:
- 定义标识变量
isCheckedAll:false,//是否勾选了全选
delArr:[]//批量删除的商品id
- 在checkbox上绑定v-model指令
<input v-show="isBatchDel" type="checkbox" :value="good.id" v-model="delArr" />
<label v-show="isBatchDel">全选<input type="checkbox" v-model="isCheckedAll" /></label>
注:如果是一个独立的复选框,选中后v-model得到的值是true,反之为false;如果是一个组的复选框 ,v-model=“数组” ,就会把选中的这个复选框的value值放入数组中,如果取消选中,会自动删除对应的value值。
- 实现全选/全不选功能
quanxuan(){
if(!this.isCheckedAll){//勾选了全选
//勾选所有商品---把所有的商品id放入都delArr中
for(let item of this.goodsArr){
this.delArr.push(item.id);
}
}else{//取消了全选
//把delArr置空即可
this.delArr=[];
}
}
- 批量删除
<button v-show="isBatchDel" class="btn btn-danger" @click="batchDel()">确定</button>
//批量删除
batchDel(){
//遍历要删除的列表
for(let id of this.delArr){
//遍历所有的商品列表
for(let i in this.goodsArr){
//进行匹配,匹配成功后删除
if(id==this.goodsArr[i].id){
this.goodsArr.splice(i,1);
break;
}
}
}
}
清空购物车
<button class="btn btn-danger" @click="goodsArr=[]">清空购物车</button>
总结
本文实现了一个非常基础的购物车模型,用vue.js实现,这也算是入门级别的,其实,由于本人也是刚接触vue,想通过写文章做笔记的形式来巩固所学知识,若文中存在错误,还请提出指教。更多的学习可以到vue的官网,查看官方文档对学习更有帮助哦。
下面对本文中的部分知识进行总结:
- ES6 for循环语法
- for_in
如:
for(let i in this.goodsArr){
if(id==this.goodsArr[i].id){
this.goodsArr.splice(i,1);
}
}
注:此方式的for循环为带下标的for循环
- for_of
for(let item of this.goodsArr){
money+=item.price*item.num;
}
注:此方式的for循环相当于foreach循环
最后,附上本次练习的源码与效果图:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>购物车</title>
<link rel="stylesheet" type="text/css" href="../../Bootstrap/bootstrap-3.3.7-dist/css/bootstrap.css"/>
<script src="../../jquery_qqchat/js/jquery-3.4.1.js" type="text/javascript" charset="utf-8"></script>
<script src="../../Bootstrap/bootstrap-3.3.7-dist/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<div class="container">
<div v-show="goodsArr.length!=0" class="table-responsive">
<table class="table table-hover " border="0" cellspacing="0" cellpadding="0">
<thead align="center">
<th>序号</th>
<th>商品名称</th>
<th>图片</th>
<th>单价(元)</th>
<th>总价(元)</th>
<th>数量</th>
<th>
<label v-show="isBatchDel">全选<input type="checkbox" v-model="isCheckedAll" @click="quanxuan()" /></label>
<span v-show="!isBatchDel">操作</span>
</th>
</thead>
<tr v-for="(good,index) in goodsArr">
<td>{{index+1}}</td>
<td>{{good.name}}</td>
<td><img :src="good.img" style="width: 70px;height: 70px;"></td>
<td>{{showMoney(good.price)}}</td>
<td>
{{showMoney(sum1(good.price,good.num))}}
</td>
<td>
<div class="input-group">
<button :disabled="good.num<=1" class="btn-info input-group-addon" @click="good.num--">-</button>
<input type="text" :value="good.num" size="2" readonly style="border-width:0px;background:#F5F5F5;width:25px;height: 28px;" />
<button :disabled="good.num>=10" class="btn-info input-group-addon" @click="good.num++">+</button>
</div>
</td>
<td>
<input v-show="isBatchDel" type="checkbox" :value="good.id" v-model="delArr" />
<a v-show="!isBatchDel" class="btn btn-danger" href="#" @click.prevent="remove(good.id)">移除</a>
</td>
</tr>
<tr align="center">
<td><button class="btn btn-danger" @click="goodsArr=[]">清空购物车</button></td>
<td colspan="5">合计:{{showMoney(sum2)}} </td>
<td align="left">
<button class="btn btn-danger" @click="batchDelClick()">{{btnValue}}</button>
<button v-show="isBatchDel" class="btn btn-danger" @click="batchDel()">确定</button>
</td>
</tr>
</table>
</div>
<div v-show="goodsArr.length==0" id="">
<h1 class="text-center">你的购物车空空如也,快去<a href="#">购物</a>吧!!!</h1>
</div>
</div>
</div>
</body>
<script type="text/javascript">
let vue=new Vue({
el:"#app",
data:{
goodsArr:[
{id:0,name:"小米10",img:"img/5.png",price:4000,num:1},
{id:1,name:"Redmi K30",img:"img/8.png",price:1700,num:1},
{id:2,name:"Redmi K30 5G",img:"img/7.png",price:2000,num:1},
{id:3,name:"小米CC9 Pro",img:"img/2.png",price:2600,num:1},
{id:4,name:"Redmi 8",img:"img/1.png",price:700,num:1}
],
isBatchDel:false,
btnValue:"批量删除",
isCheckedAll:false,//是否勾选了全选
delArr:[]//批量删除的商品id
},
computed:{
//合计
sum2:function(){
let money=0;
for(let item of this.goodsArr){
money+=item.price*item.num;
}
return money;
}
},
methods:{
//小计
sum1(price,num){
return price*num;
},
//单个移除
remove(id){
if(confirm("确定要移除该商品吗?")){
for(let i in this.goodsArr){
if(id==this.goodsArr[i].id){
this.goodsArr.splice(i,1);
}
}
}
},
showMoney(money){
return "¥"+money.toFixed(2);//保留数值的2位小数点
},
//点击批量删除按钮
batchDelClick(){
if(this.isBatchDel){
this.isBatchDel=false;
this.btnValue="批量删除";
}else{
this.isBatchDel=true;
this.btnValue="取消";
}
},
//全选
quanxuan(){
if(!this.isCheckedAll){//勾选了全选
//勾选所有商品---把所有的商品id放入都delArr中
for(let item of this.goodsArr){
this.delArr.push(item.id);
}
}else{//取消了全选
//把delArr置空即可
this.delArr=[];
}
},
//批量删除
batchDel(){
//遍历要删除的列表
for(let id of this.delArr){
//遍历所有的商品列表
for(let i in this.goodsArr){
//进行匹配,匹配成功后删除
if(id==this.goodsArr[i].id){
this.goodsArr.splice(i,1);
break;
}
}
}
}
}
});
</script>
</html>