最近学习在学由梁灏著作的Vue.js实战,其中有一章讲述如何用Vue开发购物车的章节,即课后练习,以下书中的开发过程即本人的课后练习,希望能对你学习Vue有所帮助。
购物车的基本功能
通过增加或减少商品的数量来控制商品总价
css样式
[v-cloak]{
display: none;
}
table {
border: :1px solid #e9e9e9;
border-collapse:collapse ;
border-spacing:0 ;
empty-cells: show;
}
th{
background: #f7f7f7;
color: #5c6b77;
font-weight: 600;
white-space: nowrap;
border: :1px solid #eee;
}
th,td{
padding: 8px 16px;
text-align: center;
border: 1px solid #eee;
}
练习一:在当前示例基础上扩展商品列表,新增一项是否选中功能,总价变为只计算当前选中商品的价格,同时提供一个全选的按钮。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../../../js/vue.js"></script>
<link href="cart.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="app" v-cloak>
<template v-if="list.length">
<table>
<thead>
<tr>
<th><input type="radio" :checked="checkAll" @click="handleSelectAll"></input></th>
<th>商品名称</th>
<th>商品单价</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in list">
<td><input type="radio" :checked="item.checked" @click="handleSelect(index)"></input>
</td>
<td>{{item.name}}</td>
<td>{{item.price}}</td>
<td>
<button @click="handleReduce(index)" :disabled="item.count===1">-</button>
{{item.count}}
<button @click="handleAdd(index)" :disabled="item.count===9">+</button>
</td>
<td>
<button @click="handlerRemove(index)">移除</button>
</td>
</tr>
</tbody>
</table>
<div>总价¥{{totalPrice}}</div>
</template>
<div v-else>购物车为空</div>
</div>
<script src="cart.js"></script>
</body>
</html>
var dataList = [{
id: 1,
name: "iphone 7",
price: 5000,
count: 1,
checked: false
}, {
id: 2,
name: "iPad Pro",
price: 5888,
count: 1,
checked: false
},{
id: 3,
name: "MacBook Pro",
price: 21488,
count: 1,
checked: false
}]
var vm = new Vue({
el: "#app",
data: {
list: dataList,
checkAll: false
},
computed: {
totalPrice: {
get: function() {
var total = 0;
for (var i = 0; i < this.list.length; i++) {
var item = this.list[i];
if (item.checked) {
total += item.price * item.count;
}
}
return total.toString().replace(/\B(?=(\d{3})+$)/g, ',');
}
},
},
methods: {
handleReduce: function(index) {
if (this.list[index].count === 1) return;
this.list[index].count--;
},
handleAdd: function(index) {
this.list[index].count++;
},
handlerRemove: function(index) {
this.list.splice(index, 1);
},
handleSelect: function(index) {
var item = this.list[index],
thisCheck = item.checked;
item.checked = !thisCheck;
if (thisCheck) {
this.checkAll = false;
} else {
var checkList = this.list.find(function(item) {
return item.checked === false;
});
if (typeof checkList=="undefined") {
this.checkAll = true;
}
}
},
handleSelectAll: function() {
var checkAll = !this.checkAll;
for (var item of this.list) {
item.checked = checkAll;
}
this.checkAll = checkAll;
}
}
})
练习二:将商品列表list改为一个二维数组来实现商品的分类,比如可分为“电子产品”,“生活用品”,“果蔬”,同类产品聚合在一起。提示你可能会用到二次v-for
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link href="cart.css" rel="stylesheet" type="text/css" />
<script src="../../../js/vue.js"></script>
</head>
<body>
<div id="app" v-cloak>
<template v-if="list.length">
<table>
<thead>
<tr>
<th>商品分类</th>
<th><input type="radio" :checked="checkAll" @click="handleSelectAll">全选</input></th>
<th>商品名称</th>
<th>商品单价</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<template v-for="(item,index) in list">
<tbody>
<tr>
<td colspan="6" style="text-align: left;">{{ item[0] }}</td>
</tr>
<tr v-for="(item1,index2) in item[1]">
<td></td>
<td><input type="radio" :checked="item1.checked" @click="handlerSelect(index,index2)"></input></td>
<td>{{item1.name}}</td>
<td>{{item1.price}}</td>
<td><button @click="handleReduce(index,index2)" :disabled="item1.count===1">-</button>
{{item1.count}}
<button @click="handleAdd(index,index2)">+</button>
</td>
<td><button @click="handlerRemove(index,index2)">移除</button></td>
</tr>
</tbody>
</template>
</table>
<div>{{totalPrice}}</div>
</template>
<div v-else>购物车为空</div>
</div>
<script src="cart2.js"></script>
</body>
</html>
var dataList = [
[
"电子产品",
[{
id: 1,
name: "iphone 7",
price: 5000,
count: 1,
checked: false
}, {
id: 2,
name: "iPad Pro",
price: 5888,
count: 1,
checked: false
}, {
id: 3,
name: "MacBook Pro",
price: 21488,
count: 1,
checked: false
}]
],
[
"生活用品",
[{
id: 1,
name: "牙膏",
price: 16,
count: 1,
checked: false
}, {
id: 2,
name: "脸盆",
price: 10,
count: 1,
checked: false
}, {
id: 3,
name: "拖把",
price: 70,
count: 1,
checked: false
}]
],
[
"果蔬",
[{
id: 1,
name: "苹果",
price: 1,
count: 1,
checked: false
}, {
id: 2,
name: "香蕉",
price: 0.8,
count: 1,
checked: false
}, {
id: 3,
name: "橘子",
price: 0.6,
count: 1,
checked: false
}]
]
]
var vm = new Vue({
el: "#app",
data: {
list: dataList,
checkAll: false,
},
methods: {
handleAdd: function(index, index2) {
this.list[index][1][index2].count++;
},
handleReduce: function(index, index2) {
if (this.list[index][1][index2].count == 1) return;
this.list[index][1][index2].count--;
},
handlerRemove: function(index, index2) {
var _list = this.list[index],
_list_01 = _list[1];
_list_01.splice(index2, 1);
if (_list_01.length == 0) {
this.list.splice(index, 1);
}
},
handlerSelect: function(index, index2) {
var _list = this.list[index],
_list_01 = _list[1][index2],
_checked = _list_01.checked;
_list_01.checked = !_checked;
if (_checked) {
this.checkAll = false;
} else {
var checkList = this.list.find(function(item) {
return item[1].find(function(item_01) {
return item_01.checked === false;
})
});
if (typeof checkList == "undefined") {
this.checkAll = true;
}
}
},
handleSelectAll: function() {
var checkAll = !this.checkAll;
for (var item of this.list) {
for(var item_01 of item[1]){
item_01.checked=checkAll;
}
}
this.checkAll = checkAll;
}
},
computed: {
totalPrice: function() {
var total = 0;
for (var item of this.list) {
var list_01 = item[1];
for (var item_01 of list_01) {
if (item_01.checked) {
total += item_01.price * item_01.count;
}
}
}
return total.toFixed(2).toString().replace(/\B(?=(\d{3})+$)/g, ',');;
}
}
})