效果
练习 1
给list里面的每个元素加一个属性来标记是否被选择
在每行的最后一栏加个复选框,标记是否选中(用函数更改元素的标记属性),复选框也要随之更改,
然后在 computed 把没有选中的过滤一下
对于全选,在最下面也做一个复选框,同时在data中增加一个是否被全选的标记,
如果已经被全选了,就全部取消,否则就全选
循环遍历更改一下标记即可
最后记得把标记取反
练习 2
v-for 的多重循环 用 template 实现,然后注意把list格式调成二维的,并给每一维增加一个name
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title> 购物车示例 </title>
<link rel="stylesheet" type="text/css" href="css/style.css" />
</head>
<body>
<div id="app" v-cloak>
<template v-if="list.length">
<table>
<thead>
<tr>
<th></th>
<th> 商品名称 </th>
<th> 商品单价 </th>
<th> 购买数量 </th>
<th> 操作 </th>
<th> 选择 </th>
</tr>
</thead>
<tbody>
<template v-for="(item1,index1) in list">
<tr>
<th>
{{ item1.name }}
</th>
</tr>
<tr v-for="(item2,index2) in list[index1].content">
<td>
{{ item2.id }}
</td>
<td>
{{ item2.name }}
</td>
<td>
{{ item2.price }}
</td>
<td>
<button
@click="handleReduce(index1,index2)"
:disabled="item2.count === 1"> -
</button>
{{ item2.count }}
<button
@click="handleAdd(index1,index2)">+</button>
</td>
<td>
<button @click="handleRemove(index1,index2)">移除</button>
</td>
<td>
<input type="checkbox" @click="select(index1,index2)" :checked="checked(index1,index2)" />
</td>
</tr>
</template>
</tbody>
</table>
<div>
<input type="checkbox" @click="select_all()"/> 全选
</div>
<div> 总价:¥ {{ totalPrice }}</div>
</template>
<div v-else>
购物车为空
</div>
</div>
<script src="js/vue.min.js"></script>
<script src="js/index.js"></script>
</body>
</html>
index.js
var app = new Vue({
el:'#app',
data:{
// 全选标记
select_all_flag:true,
list:[
{
name:'电子产品',
content:[
// 电子产品
{
id:1,
name:'iPhone 7',
price:6188,
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,
},
],
},
{
name:'生活用品',
content:[
// 生活用品
{
id:1,
name:'牙刷',
price:10,
count:1,
checked:false,
},
{
id:2,
name:'毛巾',
price:20,
count:1,
checked:false,
},
],
},
{
name:'果蔬',
content:[
// 果蔬
{
id:1,
name:'苹果',
price:5,
count:1,
checked:false,
},
{
id:2,
name:'香蕉',
price:10,
count:1,
checked:false,
}
],
},
],
},
computed:{
totalPrice:function() {
let total = 0
for(let i = 0;i < this.list.length; ++i) {
for(let j = 0;j < this.list[i].content.length; ++j) {
if(this.list[i].content[j].checked === false) continue
total += this.list[i].content[j].count * this.list[i].content[j].price
}
}
// 正则表达式转化
return total.toString().replace(/\B(?=(\d{3})+$)/g,',')
},
},
methods:{
handleReduce:function(index1,index2) {
if(this.list[index1].content[index2].count === 1) return
this.list[index1].content[index2].count --
},
handleAdd:function(index1,index2) {
this.list[index1].content[index2].count ++
},
handleRemove:function(index1,index2) {
this.list[index1].content.splice(index2,1)
},
// 改变商品的状态
select:function(index1,index2) {
this.list[index1].content[index2].checked === true ? this.list[index1].content[index2].checked = false : this.list[index1].content[index2].checked = true
},
// 返回商品的状态
checked:function(index1,index2) {
return this.list[index1].content[index2].checked
},
// 全选
select_all:function() {
let flag = this.select_all_flag
for(let i = 0;i < this.list.length; ++i) {
for(let j = 0;j < this.list[i].content.length; ++j) {
if(this.list[i].content[j].checked != flag) {
this.list[i].content[j].checked = flag
}
}
}
this.select_all_flag === true ? this.select_all_flag = false : this.select_all_flag = true
}
},
})
style.css
[v-cloak] {
display: none;
}
table {
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
}
th,td {
padding: 8px 16px;
border: 1px solid #E9E9E9;
text-align: left;
}
th {
background: #f7f7f7;
color: #5c6b77;
font-weight: 600;
white-space: nowrap;
}