阶段案例系列:
案例 | 链接 |
---|---|
【前端】vue阶段案例:购物车 | https://blog.csdn.net/karshey/article/details/127473654 |
【前端】vue阶段案例:父子组件通信-tabControl栏 | https://blog.csdn.net/karshey/article/details/127480941 |
【前端】vue阶段案例:组件化-房源展示 | https://blog.csdn.net/karshey/article/details/127520175 |
【前端】vue阶段案例:vue-router使用流程 | https://blog.csdn.net/karshey/article/details/127554171 |
目标
- 购物车表单
- 可以添加、减少购买数量,在数字为0时不能继续减少
- 自动结算总价格
- 移除按钮
- 点某行就有背景色
- 在所有元素移除后显示:购物车为空
代码
0.数据准备
把数据放到一个js中:一般都是以对象的形式存的(一本书就是一个对象)
const books = [
{
id: 1,
name: '《算法导论》',
date: '2006-9',
price: 85.00,
count: 1
},
{
id: 2,
name: '《UNIX编程艺术》',
date: '2006-2',
price: 59.00,
count: 1
},
{
id: 3,
name: '《编程珠玑》',
date: '2008-10',
price: 39.00,
count: 1
},
{
id: 4,
name: '《代码大全》',
date: '2006-3',
price: 128.00,
count: 1
},
]
1.框架结构
只有结构。
html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<div id="app">
<!-- 购物车不为空 -->
<template v-if="books.length">
<!-- 表单 -->
<table>
<thead>
<tr>
<th>序号</th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- 数据来自js里的data:一般都要绑定key -->
<tr v-for="(item,index) in books" :key="item">
<td>{{index+1}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<td>{{item.price}}</td>
<td>
<button>-</button>
{{item.count}}
<button>+</button>
</td>
<td>
<button>移除</button>
</td>
</tr>
</tbody>
</table>
<!-- 总价格 -->
<h2>总价格{{totalPrice}}</h2>
</template>
<!-- 购物车为空 -->
<template v-else>
<h2>购物车为空</h2>
</template>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="./js/data.js"></script>
<script src="./js/index.js"></script>
</body>
</html>
index.js:
const app=Vue.createApp({
data:function(){
return{
books:books
}
},
methods:{
}
})
app.mount('#app')
2.样式
加上边框,变得宽一点。
table {
border-collapse: collapse;
}
td,th {
border: 1px solid #aaa;
padding: 10px 20px;
}
3.按钮js
3.1 加减按钮
效果:点击加减按钮,中间的数字会改变。
html:
<td>
<!-- 要传参数index,不然不知道要改哪个 -->
<button :disabled="item.count<=0" @click="sub(index)">-</button>
{{item.count}}
<button @click="add(index)">+</button>
</td>
js:
// 加减
sub:function(index){
this.books[index].count--
},
add:function(index){
this.books[index].count++
},
3.2 移除按钮
效果:点击移除按钮,本行被移除。
html:
<td>
<button @click="removeItem(index)">移除</button>
</td>
js:
// 移除
removeItem:function(index){
// 从第index个开始移除1个
this.books.splice(index,1)
}
4.总价格
效果:能自动计算总价格。
js:
computed: {
// 总价格
totalPrice: function () {
// 两种方法都可以
// 参数:函数(上一个返回值,当前元素),初始值
return this.books.reduce(function (preValue, item) {
return preValue + item.price * item.count
}, 0)
// 简单版
// let sum = 0
// for (item of books) {
// sum += item.price * item.count
// }
// return sum
}
}
5.点击有背景色:排它
效果:点击某行,则此行会有背景色。其他行无背景色。
css中添加:表示添加了这个active类的会改变背景颜色。
.active{
background-color: azure;
}
html:绑定了类{active:index===isActive}
,添加了点击事件@click="clickItem(index)
。
绑定类:当前的index=isActive时表达式返回true,则active:true,说明添加这个类。
<tr :class="{active:index===isActive}" @click="clickItem(index)" v-for="(item,index) in books" :key="item">
js:
data参数添加isActive: -1
,表示初始时都没有背景色。
methods参数添加如下函数,表示点谁就令isActive为谁的index,于是:对应的index的class会为true,添加active类,就有了背景色效果。 且排它(只会有一个有效果!)。
// 点击改变背景色,排它
clickItem: function (index) {
this.isActive = index
}
总代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<div id="app">
<!-- 购物车不为空 -->
<template v-if="books.length">
<!-- 表单 -->
<table>
<thead>
<tr>
<th>序号</th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- 数据来自js里的data:一般都要绑定key -->
<tr :class="{active:index===isActive}" @click="clickItem(index)" v-for="(item,index) in books" :key="item">
<td>{{index+1}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<td>{{formatPrice(item.price)}}</td>
<td>
<!-- 要传参数index,不然不知道要改哪个 -->
<button :disabled="item.count<=0" @click="sub(index)">-</button>
{{item.count}}
<button @click="add(index)">+</button>
</td>
<td>
<button @click="removeItem(index)">移除</button>
</td>
</tr>
</tbody>
</table>
<!-- 总价格 -->
<h2>总价格{{formatPrice(totalPrice)}}</h2>
</template>
<!-- 购物车为空 -->
<template v-else>
<h2>购物车为空</h2>
</template>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="./js/data.js"></script>
<script src="./js/index.js"></script>
</body>
</html>
css
table {
border-collapse: collapse;
}
td,th {
border: 1px solid #aaa;
padding: 10px 20px;
}
.active{
background-color: azure;
}
js
const app = Vue.createApp({
data: function () {
return {
books: books,
isActive: -1
}
},
methods: {
// 加¥
formatPrice: function (price) {
return "¥" + price
},
// 加减
sub: function (index) {
this.books[index].count--
},
add: function (index) {
this.books[index].count++
},
// 移除
removeItem: function (index) {
// 从第index个开始移除1个
this.books.splice(index, 1)
},
// 点击改变背景色,排它
clickItem: function (index) {
this.isActive = index
}
},
computed: {
// 总价格
totalPrice: function () {
// 两种方法都可以
// 参数:函数(上一个返回值,当前元素),初始值
return this.books.reduce(function (preValue, item) {
return preValue + item.price * item.count
}, 0)
// 简单版
// let sum = 0
// for (item of books) {
// sum += item.price * item.count
// }
// return sum
}
}
})
app.mount('#app')