利用计算属性、指令等知识开发购物车
题目描述
购物车需要展示一个已加入购物车的商品列表,包含商品名称、商品单价、购买数量、操作等信息,还需要实时显示购买的总价。其中购买的数量可以增加或减少,每类商品可以从购物车中移除。
进阶1
在上述问题的基础上,新增一项是否选中该商品的功能,总价变为只计算选中商品的总价,同时提供一个全选按钮
<!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>
<style>
[v-cloak] {
display: none;
}
table {
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
}
th,
td {
border: 1px solid #e9e9e9;
text-align: left;
}
th {
background: #f7f7f7;
color: #5c6b77;
font-weight: 600;
white-space: nowrap;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<template v-if="list.length">
<table>
<thead>
<tr>
<th><input type="checkbox" @click="swap2Checked" :checked=allChecked></th>
<th>商品名称</th>
<th>商品单价</th>
<th>商品数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in list">
<td><input type="checkbox" :checked=item.isCheck :id="item.id" :value="index"
@click="changeStatus(index)">
</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)">+</button>
</td>
<td><button @click="handleRemove(index)">移除</button></td>
</tr>
</tbody>
</table>
<div>总价:¥ {{ totalPrice }}</div>
</template>
<div v-else>购物车为空</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#app',
data() {
return {
msg: 'hello',
link: '<a href="#">this is a link</a>',
url: 'http://www.baidu.com/',
list: [
{
id: 1,
name: 'iphone x',
price: 6100,
count: 1,
isCheck: false
},
{
id: 2,
name: 'ipad pro',
price: 4000,
count: 1,
isCheck: true
},
{
id: 3,
name: 'mac pro',
price: 20100,
count: 1,
isCheck: false
}
],
allChecked: false
}
},
computed: {
totalPrice: function () {
var total = 0;
for (var i = 0; i < this.list.length; i++) {
if (this.list[i].isCheck) {
var item = this.list[i];
total += item.price * item.count;
}
}
return total;
},
// allChecked: function () {
// for (var i = 0; i < this.list.length; i++) {
// if (!this.list[i].isCheck) {
// return false
// }
// }
// return true
// }
},
methods: {
handleReduce: function (index) {
if (this.list[index].count === 1) return;
this.list[index].count--;
},
handleAdd: function (index) {
this.list[index].count++;
},
handleRemove: function (index) {
this.list.splice(index, 1);
},
swap2Checked: function () {
this.allChecked = !this.allChecked
if (this.allChecked) {
for (var i = 0; i < this.list.length; i++) {
this.list[i].isCheck = true
}
}else{
for (var i = 0; i < this.list.length; i++) {
this.list[i].isCheck = false
}
}
},
changeStatus: function (index) {
this.list[index].isCheck = !this.list[index].isCheck
var flag = true
for (var i = 0; i < this.list.length; i++) {
if(!this.list[i].isCheck){
flag = false
}
}
this.allChecked = flag
}
}
})
</script>
</body>
</html>
进阶2
将商品的列表List改为一个二维数组来实现商品的分类,比如可分为“电子商品”,“生活用品”,同类商品聚合在一起。
<!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>
<style>
[v-cloak] {
display: none;
}
table {
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
}
th,
td {
border: 1px solid #e9e9e9;
text-align: left;
}
th {
background: #f7f7f7;
color: #5c6b77;
font-weight: 600;
white-space: nowrap;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<template v-if="list.length">
<table>
<tbody v-for="(items,tableIndex) in list">
<tr>
<th><input type="checkbox" @click="swapTableChecked($event,items)"
:checked="isTableAllChecked(items)">{{items.name}}</th>
<th>商品名称</th>
<th>商品单价</th>
<th>商品数量</th>
<th>操作</th>
</tr>
<tr v-for="(item,index) in items.productList">
<td><input type="checkbox" :checked=item.isCheck :id="item.id" :value="index"
@click="changeStatus(item)">
</td>
<td>{{ item.name }}</td>
<td>{{ item.price }}</td>
<td>
<button @click="handleReduce(index,items)" :disabled="item.count === 1">-</button>
{{ item.count }}
<button @click="handleAdd(index,items)">+</button>
</td>
<td><button @click="handleRemove(index,items)">移除</button></td>
</tr>
</tbody>
</table>
<div><input type="checkbox" @click="swapAllChecked" :checked="isAllChecked()">全选</div>
<div>总价:¥ {{ totalPrice }}</div>
</template>
<div v-else>购物车为空</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#app',
data() {
return {
msg: 'hello',
link: '<a href="#">this is a link</a>',
url: 'http://www.baidu.com/',
list: [{
name: "电子产品",
productList: [{
id: '1',
name: 'iPhone 7',
price: 6188,
count: 1,
isCheck: false
},
{
id: '2',
name: 'iPad Pro',
price: 5188,
count: 1,
isCheck: false
},
{
id: '3',
name: 'MacBook Pro',
price: 21488,
count: 1,
isCheck: false
}
]
},
{
name: "生活用品",
productList: [{
id: '1',
name: '尺子',
price: 2.00,
count: 1,
isCheck: false
},
{
id: '2',
name: '包装箱',
price: 29.99,
count: 1,
isCheck: false
},
{
id: '3',
name: '毛巾',
price: 15.98,
count: 1,
isCheck: false
}
]
},
{
name: "水果蔬菜",
productList: [{
id: '1',
name: '国产香蕉',
price: 2.88,
count: 1,
isCheck: false
},
{
id: '2',
name: '草莓',
price: 15.00,
count: 1,
isCheck: false
},
{
id: '3',
name: '车厘子',
price: 29.99,
count: 1,
isCheck: false
}
]
}
],
allChecked: false
}
},
computed: {
totalPrice: function () {
var total = 0;
for (var i = 0; i < this.list.length; i++) {
for (var j = 0; j < this.list[i].productList.length; j++) {
var item = this.list[i].productList[j];
if (item.isCheck) {
total += item.price * item.count;
}
}
}
return total != 0 ? total.toString().replace(/\B(?=(\d{3})+$)/g, ',') : 0;
},
},
methods: {
handleReduce: function (index,items) {
if (items.productList[index].count === 1) return;
items.productList[index].count--;
},
handleAdd: function (index,items) {
console.log(items)
items.productList[index].count++;
},
handleRemove: function (index,items) {
items.productList.splice(index, 1);
},
swapTableChecked: function (e, items) {
console.log(e)
console.log(e.currentTarget.checked)
if (e.currentTarget.checked) {
for (var i = 0; i < items.productList.length; i++) {
items.productList[i].isCheck = true
}
} else {
for (var i = 0; i < items.productList.length; i++) {
items.productList[i].isCheck = false
}
}
},
changeStatus: function (item) {
item.isCheck = !item.isCheck
},
isTableAllChecked: function (items) {
var flag = true
for (var i = 0; i < items.productList.length; i++) {
if (!items.productList[i].isCheck) {
return false
}
}
return true
},
swapAllChecked: function (e) {
if (e.currentTarget.checked) {
for (var i = 0; i < this.list.length; i++) {
for (var j = 0; j < this.list[i].productList.length; j++) {
this.list[i].productList[j].isCheck = true;
}
}
} else {
for (var i = 0; i < this.list.length; i++) {
for (var j = 0; j < this.list[i].productList.length; j++) {
this.list[i].productList[j].isCheck = false;
}
}
}
},
isAllChecked: function () {
var flag = true
for (var i = 0; i < this.list.length; i++) {
for (var j = 0; j < this.list[i].productList.length; j++) {
if (!this.list[i].productList[j].isCheck) {
return false
}
}
}
return true
}
}
})
</script>
</body>
</html>
网友评论