一、需求说明
1.渲染功能
(1)代码
<!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" />
<link rel="stylesheet" href="./css/inputnumber.css" />
<link rel="stylesheet" href="./css/index.css" />
<title>购物车</title>
</head>
<body>
<div class="app-container" id="app">
<!-- 顶部banner -->
<div class="banner-box"><img src="img/fruit.jpg" alt="" /></div>
<!-- 面包屑 -->
<div class="breadcrumb">
<span>🏠</span>
/
<span>购物车</span>
</div>
<!-- 购物车主体 -->
<div class="main" v-if="fruitList.length > 0">
<div class="table">
<!-- 头部 -->
<div class="thead">
<div class="tr">
<div class="th">选中</div>
<div class="th th-pic">图片</div>
<div class="th">单价</div>
<div class="th num-th">个数</div>
<div class="th">小计</div>
<div class="th">操作</div>
</div>
</div>
<!-- 身体 -->
<div class="tbody">
<div v-for="(item, index) in fruitList" :key="item.id" class="tr" :class="{ active: item.isChecked }">
<div class="td"><input type="checkbox" v-model="item.isChecked" /></div>
<div class="td"><img :src="item.icon" alt="" /></div>
<div class="td">{{ item.price }}</div>
<div class="td">
<div class="my-input-number">
<button class="decrease"> - </button>
<span class="my-input__inner">{{ item.num }}</span>
<button class="increase"> + </button>
</div>
</div>
<div class="td">{{ item.num * item.price }}</div>
<div class="td"><button>删除</button></div>
</div>
</div>
</div>
<!-- 底部 -->
<div class="bottom">
<!-- 全选 -->
<label class="check-all">
<input type="checkbox" />
全选
</label>
<div class="right-box">
<!-- 所有商品总价 -->
<span class="price-box">总价 : ¥ <span class="price">24</span></span>
<!-- 结算按钮 -->
<button class="pay">结算( 6 )</button>
</div>
</div>
</div>
<!-- 空车 -->
<div class="empty" v-else>🛒空空如也</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// 水果列表
fruitList: [
{
id: 1,
icon: 'img/火龙果.png',
isChecked: true,
num: 2,
price: 6,
},
{
id: 2,
icon: 'img/荔枝.png',
isChecked: false,
num: 7,
price: 20,
},
{
id: 3,
icon: 'img/榴莲.png',
isChecked: false,
num: 3,
price: 40,
},
{
id: 4,
icon: 'img/鸭梨.png',
isChecked: true,
num: 10,
price: 3,
},
{
id: 5,
icon: 'img/樱桃.png',
isChecked: false,
num: 20,
price: 34,
},
],
},
})
</script>
</body>
</html>
(2)展示
2.删除和修改数量
(1)代码
<!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" />
<link rel="stylesheet" href="./css/inputnumber.css" />
<link rel="stylesheet" href="./css/index.css" />
<title>购物车</title>
</head>
<body>
<div class="app-container" id="app">
<!-- 顶部banner -->
<div class="banner-box"><img src="img/fruit.jpg" alt="" /></div>
<!-- 面包屑 -->
<div class="breadcrumb">
<span>🏠</span>
/
<span>购物车</span>
</div>
<!-- 购物车主体 -->
<div class="main" v-if="fruitList.length > 0">
<div class="table">
<!-- 头部 -->
<div class="thead">
<div class="tr">
<div class="th">选中</div>
<div class="th th-pic">图片</div>
<div class="th">单价</div>
<div class="th num-th">个数</div>
<div class="th">小计</div>
<div class="th">操作</div>
</div>
</div>
<!-- 身体 -->
<div class="tbody">
<div v-for="(item, index) in fruitList" :key="item.id" class="tr" :class="{ active: item.isChecked }">
<div class="td"><input type="checkbox" v-model="item.isChecked" /></div>
<div class="td"><img :src="item.icon" alt="" /></div>
<div class="td">{{ item.price }}</div>
<div class="td">
<div class="my-input-number">
<button :disabled="item.num <=1" class="decrease" @click="sub(item.id)"> - </button>
<span class="my-input__inner">{{ item.num }}</span>
<button class="increase" @click="add(item.id)"> + </button>
</div>
</div>
<div class="td">{{ item.num * item.price }}</div>
<div class="td"><button @click="del(item.id)">删除</button></div>
</div>
</div>
</div>
<!-- 底部 -->
<div class="bottom">
<!-- 全选 -->
<label class="check-all">
<input type="checkbox" />
全选
</label>
<div class="right-box">
<!-- 所有商品总价 -->
<span class="price-box">总价 : ¥ <span class="price">24</span></span>
<!-- 结算按钮 -->
<button class="pay">结算( 6 )</button>
</div>
</div>
</div>
<!-- 空车 -->
<div class="empty" v-else>🛒空空如也</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// 水果列表
fruitList: [
{
id: 1,
icon: 'img/火龙果.png',
isChecked: true,
num: 2,
price: 6,
},
{
id: 2,
icon: 'img/荔枝.png',
isChecked: false,
num: 7,
price: 20,
},
{
id: 3,
icon: 'img/榴莲.png',
isChecked: false,
num: 3,
price: 40,
},
{
id: 4,
icon: 'img/鸭梨.png',
isChecked: true,
num: 10,
price: 3,
},
{
id: 5,
icon: 'img/樱桃.png',
isChecked: false,
num: 20,
price: 34,
},
],
},
methods:{
del(id){
this.fruitList = this.fruitList.filter(item => item.id !== id)
},
add(id){
//1.根据id 找到数组中的对应项 -> find
const fruit = this.fruitList.find(item => item.id === id)
//2.操作num数量
fruit.num++
// console.log(id)
},
sub(id){
//1.根据id 找到数组中的对应项 -> find
const fruit = this.fruitList.find(item => item.id === id)
//2.操作num数量
fruit.num--
// console.log(id)
}
},
})
</script>
</body>
</html>
(2)展示
减到1就不能再减,点击删除直接删除
3.全选与反选
(1)代码
<!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" />
<link rel="stylesheet" href="./css/inputnumber.css" />
<link rel="stylesheet" href="./css/index.css" />
<title>购物车</title>
</head>
<body>
<div class="app-container" id="app">
<!-- 顶部banner -->
<div class="banner-box"><img src="img/fruit.jpg" alt="" /></div>
<!-- 面包屑 -->
<div class="breadcrumb">
<span>🏠</span>
/
<span>购物车</span>
</div>
<!-- 购物车主体 -->
<div class="main" v-if="fruitList.length > 0">
<div class="table">
<!-- 头部 -->
<div class="thead">
<div class="tr">
<div class="th">选中</div>
<div class="th th-pic">图片</div>
<div class="th">单价</div>
<div class="th num-th">个数</div>
<div class="th">小计</div>
<div class="th">操作</div>
</div>
</div>
<!-- 身体 -->
<div class="tbody">
<div v-for="(item, index) in fruitList" :key="item.id" class="tr" :class="{ active: item.isChecked }">
<div class="td"><input type="checkbox" v-model="item.isChecked" /></div>
<div class="td"><img :src="item.icon" alt="" /></div>
<div class="td">{{ item.price }}</div>
<div class="td">
<div class="my-input-number">
<button :disabled="item.num <=1" class="decrease" @click="sub(item.id)"> - </button>
<span class="my-input__inner">{{ item.num }}</span>
<button class="increase" @click="add(item.id)"> + </button>
</div>
</div>
<div class="td">{{ item.num * item.price }}</div>
<div class="td"><button @click="del(item.id)">删除</button></div>
</div>
</div>
</div>
<!-- 底部 -->
<div class="bottom">
<!-- 全选 -->
<label class="check-all">
<input type="checkbox" v-model="isAll"/>
全选
</label>
<div class="right-box">
<!-- 所有商品总价 -->
<span class="price-box">总价 : ¥ <span class="price">24</span></span>
<!-- 结算按钮 -->
<button class="pay">结算( 6 )</button>
</div>
</div>
</div>
<!-- 空车 -->
<div class="empty" v-else>🛒空空如也</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// 水果列表
fruitList: [
{
id: 1,
icon: 'img/火龙果.png',
isChecked: true,
num: 2,
price: 6,
},
{
id: 2,
icon: 'img/荔枝.png',
isChecked: false,
num: 7,
price: 20,
},
{
id: 3,
icon: 'img/榴莲.png',
isChecked: false,
num: 3,
price: 40,
},
{
id: 4,
icon: 'img/鸭梨.png',
isChecked: true,
num: 10,
price: 3,
},
{
id: 5,
icon: 'img/樱桃.png',
isChecked: false,
num: 20,
price: 34,
},
],
},
computed:{
//默认计算属性,只能能获取不能设置,要设置需要写完整写法
// isAll(){
// //必须所有的小选框都选中,全选按钮才选中 ------>every
// return this.fruitList.every(item => item.isChecked)
// },
// 完整写法 => get+set
isAll:{
get(){
return this.fruitList.every(item => item.isChecked)
},
set(value){
//基于拿到的布尔值,要让所有的小选框 同步状态
this.fruitList.forEach(item => item.isChecked = value)
// console.log(value)
},
}
},
methods:{
del(id){
this.fruitList = this.fruitList.filter(item => item.id !== id)
},
add(id){
//1.根据id 找到数组中的对应项 -> find
const fruit = this.fruitList.find(item => item.id === id)
//2.操作num数量
fruit.num++
// console.log(id)
},
sub(id){
//1.根据id 找到数组中的对应项 -> find
const fruit = this.fruitList.find(item => item.id === id)
//2.操作num数量
fruit.num--
// console.log(id)
}
},
})
</script>
</body>
</html>
(2)展示
4.统计选中的总价和总数量
(1)代码
<!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" />
<link rel="stylesheet" href="./css/inputnumber.css" />
<link rel="stylesheet" href="./css/index.css" />
<title>购物车</title>
</head>
<body>
<div class="app-container" id="app">
<!-- 顶部banner -->
<div class="banner-box"><img src="img/fruit.jpg" alt="" /></div>
<!-- 面包屑 -->
<div class="breadcrumb">
<span>🏠</span>
/
<span>购物车</span>
</div>
<!-- 购物车主体 -->
<div class="main" v-if="fruitList.length > 0">
<div class="table">
<!-- 头部 -->
<div class="thead">
<div class="tr">
<div class="th">选中</div>
<div class="th th-pic">图片</div>
<div class="th">单价</div>
<div class="th num-th">个数</div>
<div class="th">小计</div>
<div class="th">操作</div>
</div>
</div>
<!-- 身体 -->
<div class="tbody">
<div v-for="(item, index) in fruitList" :key="item.id" class="tr" :class="{ active: item.isChecked }">
<div class="td"><input type="checkbox" v-model="item.isChecked" /></div>
<div class="td"><img :src="item.icon" alt="" /></div>
<div class="td">{{ item.price }}</div>
<div class="td">
<div class="my-input-number">
<button :disabled="item.num <=1" class="decrease" @click="sub(item.id)"> - </button>
<span class="my-input__inner">{{ item.num }}</span>
<button class="increase" @click="add(item.id)"> + </button>
</div>
</div>
<div class="td">{{ item.num * item.price }}</div>
<div class="td"><button @click="del(item.id)">删除</button></div>
</div>
</div>
</div>
<!-- 底部 -->
<div class="bottom">
<!-- 全选 -->
<label class="check-all">
<input type="checkbox" v-model="isAll"/>
全选
</label>
<div class="right-box">
<!-- 所有商品总价 -->
<span class="price-box">总价 : ¥ <span class="price">{{ totalPrice }}</span></span>
<!-- 结算按钮 -->
<button class="pay">结算{{ totalCount }}</button>
</div>
</div>
</div>
<!-- 空车 -->
<div class="empty" v-else>🛒空空如也</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// 响应式数据
// 水果列表
fruitList: [
{
id: 1,
icon: 'img/火龙果.png',
isChecked: true,
num: 2,
price: 6,
},
{
id: 2,
icon: 'img/荔枝.png',
isChecked: false,
num: 7,
price: 20,
},
{
id: 3,
icon: 'img/榴莲.png',
isChecked: false,
num: 3,
price: 40,
},
{
id: 4,
icon: 'img/鸭梨.png',
isChecked: true,
num: 10,
price: 3,
},
{
id: 5,
icon: 'img/樱桃.png',
isChecked: false,
num: 20,
price: 34,
},
],
},
computed:{
// 计算属性
//默认计算属性,只能能获取不能设置,要设置需要写完整写法
// isAll(){
// //必须所有的小选框都选中,全选按钮才选中 ------>every
// return this.fruitList.every(item => item.isChecked)
// },
// 完整写法 => get+set
isAll:{
get(){
return this.fruitList.every(item => item.isChecked)
},
set(value){
//基于拿到的布尔值,要让所有的小选框 同步状态
this.fruitList.forEach(item => item.isChecked = value)
// console.log(value)
},
},
// 统计选中的总数
totalCount(){
return this.fruitList.reduce((sum,item) => {
if (item.isChecked){
// 选中 -> 需要累加
return sum +item.num
} else {
// 没选中 -> 不需要累加
return sum
}
},0)
},
// 统计选中的总价
totalPrice(){
return this.fruitList.reduce((sum,item) => {
if(item.isChecked){
return sum + item.num * item.price
}else{
return sum
}
},0)
},
},
methods:{
del(id){
this.fruitList = this.fruitList.filter(item => item.id !== id)
},
add(id){
//1.根据id 找到数组中的对应项 -> find
const fruit = this.fruitList.find(item => item.id === id)
//2.操作num数量
fruit.num++
// console.log(id)
},
sub(id){
//1.根据id 找到数组中的对应项 -> find
const fruit = this.fruitList.find(item => item.id === id)
//2.操作num数量
fruit.num--
// console.log(id)
},
},
})
</script>
</body>
</html>
这里写三元表达式也可以
三元表达式是一种在许多编程语言中常见的条件表达式,它由三个操作数组成:一个条件表达式、一个真值表达式和一个假值表达式。其一般形式为:
condition ? expr1 : expr2
如果写成if...else
if (condition) {
result = expr1;
} else {
result = expr2;
}
三元写法
result = condition ? expr1 : expr2;
(2)展示
被勾选的被计算
5.持久化本地
如果用户对其操作之后 没有持久化刷新后就会成问题
(1)代码
<!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" />
<link rel="stylesheet" href="./css/inputnumber.css" />
<link rel="stylesheet" href="./css/index.css" />
<title>购物车</title>
</head>
<body>
<div class="app-container" id="app">
<!-- 顶部banner -->
<div class="banner-box"><img src="img/fruit.jpg" alt="" /></div>
<!-- 面包屑 -->
<div class="breadcrumb">
<span>🏠</span>
/
<span>购物车</span>
</div>
<!-- 购物车主体 -->
<div class="main" v-if="fruitList.length > 0">
<div class="table">
<!-- 头部 -->
<div class="thead">
<div class="tr">
<div class="th">选中</div>
<div class="th th-pic">图片</div>
<div class="th">单价</div>
<div class="th num-th">个数</div>
<div class="th">小计</div>
<div class="th">操作</div>
</div>
</div>
<!-- 身体 -->
<div class="tbody">
<div v-for="(item, index) in fruitList" :key="item.id" class="tr" :class="{ active: item.isChecked }">
<div class="td"><input type="checkbox" v-model="item.isChecked" /></div>
<div class="td"><img :src="item.icon" alt="" /></div>
<div class="td">{{ item.price }}</div>
<div class="td">
<div class="my-input-number">
<button :disabled="item.num <=1" class="decrease" @click="sub(item.id)"> - </button>
<span class="my-input__inner">{{ item.num }}</span>
<button class="increase" @click="add(item.id)"> + </button>
</div>
</div>
<div class="td">{{ item.num * item.price }}</div>
<div class="td"><button @click="del(item.id)">删除</button></div>
</div>
</div>
</div>
<!-- 底部 -->
<div class="bottom">
<!-- 全选 -->
<label class="check-all">
<input type="checkbox" v-model="isAll"/>
全选
</label>
<div class="right-box">
<!-- 所有商品总价 -->
<span class="price-box">总价 : ¥ <span class="price">{{ totalPrice }}</span></span>
<!-- 结算按钮 -->
<button class="pay">结算{{ totalCount }}</button>
</div>
</div>
</div>
<!-- 空车 -->
<div class="empty" v-else>🛒空空如也</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const defaultArr = [
{
id: 1,
icon: 'img/火龙果.png',
isChecked: false,
num: 1,
price: 6,
},
{
id: 2,
icon: 'img/荔枝.png',
isChecked: false,
num: 1,
price: 20,
},
{
id: 3,
icon: 'img/榴莲.png',
isChecked: false,
num: 1,
price: 40,
},
{
id: 4,
icon: 'img/鸭梨.png',
isChecked: false,
num: 1,
price: 3,
},
{
id: 5,
icon: 'img/樱桃.png',
isChecked: false,
num: 1,
price: 34,
},
]
const app = new Vue({
el: '#app',
data: {
// 响应式数据
// 水果列表
fruitList: JSON.parse(localStorage.getItem('list')) || (defaultArr),
},
computed:{
// 计算属性
//默认计算属性,只能能获取不能设置,要设置需要写完整写法
// isAll(){
// //必须所有的小选框都选中,全选按钮才选中 ------>every
// return this.fruitList.every(item => item.isChecked)
// },
// 完整写法 => get+set
isAll:{
get(){
return this.fruitList.every(item => item.isChecked)
},
set(value){
//基于拿到的布尔值,要让所有的小选框 同步状态
this.fruitList.forEach(item => item.isChecked = value)
// console.log(value)
},
},
// // 统计选中的总数
// totalCount(){
// return this.fruitList.reduce((sum,item) => {
// if (item.isChecked){
// // 选中 -> 需要累加
// return sum +item.num
// } else {
// // 没选中 -> 不需要累加
// return sum
// }
// },0)
// },
// // 统计选中的总价
// totalPrice(){
// return this.fruitList.reduce((sum,item) => {
// if(item.isChecked){
// return sum + item.num * item.price
// }else{
// return sum
// }
// },0)
// },
//三元表达式
// 统计选中的总数
totalCount() {
return this.fruitList.reduce((sum, item) => {
return item.isChecked ? sum + item.num : sum;
}, 0);
},
// 统计选中的总价
totalPrice() {
return this.fruitList.reduce((sum, item) => {
return item.isChecked ? sum + item.num * item.price : sum;
}, 0);
},
},
methods:{
del(id){
this.fruitList = this.fruitList.filter(item => item.id !== id)
},
add(id){
//1.根据id 找到数组中的对应项 -> find
const fruit = this.fruitList.find(item => item.id === id)
//2.操作num数量
fruit.num++
// console.log(id)
},
sub(id){
//1.根据id 找到数组中的对应项 -> find
const fruit = this.fruitList.find(item => item.id === id)
//2.操作num数量
fruit.num--
// console.log(id)
},
},
watch:{
fruitList:{
deep:true,
handler(newValue){
// 需要将变化后的newValue 存入本地 (转json)
localStorage.setItem('list',JSON.stringify(newValue))
}
}
}
})
</script>
</body>
</html>
如果没有 || (defaultArr)清除缓存后就会null崩溃 ,加上之后就会默认回到初试页面了
(2)展示
6.总结
注:本人是根据黑马程序员的B站教程来学习的,
链接:https://www.bilibili.com/video/BV1HV4y1a7n4/?spm_id_from=333.999.0.0
本文章仅仅是个人学习笔记 无任何其他用途 特此说明