购物车
效果说明:
-
选中全选 下面的选择框会跟着选中 ,全选取消,下面的选择框也会跟着取消,在选中或者未选中时,总件数,总价格会随之变化, -
点击加号按钮,商品数量会增加,当达到库存量时,加号按钮禁用,点击减号按钮商品数量会减少,当数量为1时,减号按钮禁用,点击过程中,总件数,总价格会随之变化, -
点击删除按钮,该行数据会被删除 -
点击清空购物车,全部数据被删除 -
点击结算,将总价格打印在后台 -
点击删除所有选中,选中的数据将被删除 -
在操作各功能的的时候,总件数、总价格都会发生变化 -
最后将操作数据存储在本地
html 结构
<div class="header">页面顶部</div>
<div class="content">
<!-- JS渲染 -->
<!-- <div class="top">
<input type="checkbox"> 全选
</div>
<ul>
<li>
<div class="status">
<input type="checkbox">
</div>
<div class="show">
<img src="" alt="">
</div>
<div class="title">
asdhgaskjhdgkjasd
</div>
<div class="price">
¥ 100.00
</div>
<div class="number">
<button>-</button>
<input type="text" value="1">
<button>+</button>
</div>
<div class="sub">
¥ 100.00
</div>
<div class="destory">
<button>删除</button>
</div>
</li>
</ul>
<div class="bottom">
<div class="totalNum">
总件数 : 3
</div>
<div class="btns">
<button>清空购物车</button>
<button>去结算</button>
<button>删除所有已选中</button>
</div>
<div class="totalPrice">
总价格 : ¥ <span>100.00</span>
</div>
</div> -->
</div>
<div class="footer">页面底部</div>
<!-- 引入js -->
<script src="./购物车.js"></script>
css 样式
* {
margin: 0;
padding: 0;
}
ul,
ol,
li {
list-style: none;
}
.header,
.footer {
width: 1200px;
height: 100px;
background-color: skyblue;
color: #fff;
font-size: 50px;
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
}
.footer {
height: 400px;
}
/* 内容部分 */
.content {
width: 1200px;
margin: 0 auto;
padding: 10px 0;
}
.content > .top,
.content > .bottom {
height: 50px;
background-color: pink;
display: flex;
align-items: center;
}
.content > .bottom {
justify-content: space-between;
box-sizing: border-box;
padding: 0 10px;
}
.content > .bottom > .totalPrice > span {
font-size: 20px;
color: red;
}
.content > .bottom > .btns > button {
font-size: 18px;
padding: 5px 10px;
cursor: pointer;
}
.content > .top > input {
width: 30px;
height: 30px;
margin: 0 15px 0 50px;
}
.content > ul {
padding-top: 10px;
}
.content > ul > li {
width: 100%;
border: 1px solid #333;
box-sizing: border-box;
height: 100px;
margin-bottom: 10px;
display: flex;
}
.content > ul > li > div {
display: flex;
justify-content: center;
align-items: center;
border-right: 1px solid #333;
}
.content > ul > li > div:last-child {
border: none;
}
.content > ul > li > .show,
.content > ul > li > .status {
width: 100px;
}
.content > ul > li > .status > input {
width: 30px;
height: 30px;
}
.content > ul > li > .show > img {
width: 100%;
height: 100%;
display: block;
}
.content > ul > li > .price,
.content > ul > li > .sub {
width: 200px;
color: red;
font-size: 20px;
}
.content > ul > li > .title {
width: 300px;
align-items: flex-start;
justify-content: flex-start;
box-sizing: border-box;
padding: 5px;
}
.content > ul > li > .number {
width: 230px;
}
.content > ul > li > .number > input {
width: 50px;
height: 30px;
text-align: center;
margin: 0 5px;
border: none;
outline: none;
font-size: 18px;
}
.content > ul > li > .number > button {
width: 30px;
height: 30px;
cursor: pointer;
}
.content > ul > li > .destory {
flex: 1;
}
.content > ul > li > .destory > button {
padding: 5px;
font-size: 18px;
cursor: pointer;
}
分析
数组数据分析
{
id: 111234,
status: false,
pic: "https://img1.baidu.com/it/u=2511310783,721605137&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=332",
name: "我是一个手机, 不知道是啥",
price: 100,
number: 3,
total: 16,
}
- id: 数据的唯一值
- status: true代表该商品被选中, false则为没被选中
- pic: 图片地址
- name: 商品名
- price: 价格
- number: 商品收藏数量
- total: 库存
实现
* 1. 将通过数据重构页面
* 1.1 查询数据, 渲染页面
* 2. 全选
* 2.1 选中全选按钮后, 根据全选按钮的选中状态, 修改所有商品的选中状态
* 2.2 重新渲染视图
* 3. 清空购物车
* 3.1 清空商品数据
* 3.2 重新渲染视图
* 4. 结算 (将所选择商品总价计算出后打印到控制台)
* 4.1 找到所有选中的商品
* 4.2 计算所有选中商品各自的总价
* 4.3 计算所有选中商品的总价之和
* 4.4 打印到控制台
* 5. 删除已选中
* 5.1 在原数组中, 找到选中的商品, 然后删除
* 5.2 重新渲染视图
* 6. 商品数量调整
* 6.1 找到对应的商品, 修改收藏数量
* 6.2 重新渲染视图
* 7. 选中商品
* 7.1 找到对应的商品, 修改选中状态
* 7.2 重新渲染视图
* 8. 删除某一项
* 8.1 找到对应商品, 将删除
* 8.2 重新渲染视图
* 9. 数据持久化 (浏览器关闭, 数据能保存)
* 9.1 本地存储
// 再次打开可以得到的数为 原来的数据 或者 上一次操作过后的数据
var cartList = JSON.parse(window.localStorage.getItem("cartList")) || [
// 每一个对象就是一个购物车内容的数据 JSON.parse() 将字符串转换 为数组 / 再次打开页面时 展示的是上一次操作后的页面
{
id: 111234,
status: false,
pic: "https://img1.baidu.com/it/u=2511310783,721605137&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=332",
name: "我是一个手机, 不知道是啥",
price: 100,
number: 3,
total: 16,
},
{
id: 123456,
status: false,
pic: "https://img1.baidu.com/it/u=1537709578,2453227648&fm=253&fmt=auto&app=120&f=JPEG?w=809&h=500",
name: "我是一个电脑, 不知道是啥",
price: 98.72,
number: 1,
total: 7,
},
{
id: 965874,
status: false,
pic: "https://img2.baidu.com/it/u=3561506717,735421650&fm=253&fmt=auto&app=138&f=JPEG?w=750&h=500",
name: "我是一个手纸, 不知道是啥",
price: 356.21,
number: 2,
total: 22,
},
];
js 实现
var content = document.querySelector('.content'); // 获取元素
// 定义函数 渲染页面
function fun() {
// 定义变量
var selctItem = 0; // 储存商品中的数量
var selctTotalNum = 0; // 总数
var totalPrice = 0; //总价
cartList.forEach(function (item) {
if (item.status) {
selctItem++; // 选中按钮未true 数量自增
selctTotalNum += item.number; // 总数等于全部数量相加
totalPrice += item.price * item.number; //总价等于总数量*总价
}
})
var str = `
<div class="top">
<input class="quXun" type="checkbox" ${selctItem === cartList.length ? "checked" : " "}> 全选
</div>
<ul>`
// ${selctItem === cartList.length ? "checked" : " " 判断数据是否等于数组长度 ,等于赋值"checked"(即选中) 不等于 为空
// 数组遍历 将每个数组渲染到数组中
cartList.forEach(function (item) { //data-id="${item.id}" 将实时id赋给data-id data-id => h5新增属性
str += `
<li>
<div class="status">
<input class="danXun" data-id="${item.id}" type="checkbox" ${item.status ? "checked" : " "}>
</div>
<div class="show">
<img src="${item.pic}" alt="">
</div>
<div class="title">
${item.name}
</div>
<div class="price">
¥ ${item.price.toFixed(2)}
</div>
<div class="number">
<button class="jing" data-id="${item.id}">-</button>
<input type="text" value="${item.number}">
<button class="jia" data-id="${item.id}">+</button>
</div>.
<div class="sub">
¥ ${(item.price * item.number).toFixed(2)}
</div>
<div class="destory">
<button data-id="${item.id}" class="del1">删除</button>
</div>
</li>`
})
str += `
</ul>
<div class="bottom">
<div class="totalNum">
总件数 : ${selctTotalNum}
</div>
<div class="btns">
<button class="clier">清空购物车</button>
<button class="jieSun" data-totalPrice="${totalPrice.toFixed(2)}">去结算</button>
<button class="del">删除所有已选中</button>
</div>
<div class="totalPrice">
总价格 : ¥ <span>${totalPrice.toFixed(2)}</span>
</div>
</div>
`
content.innerHTML = str; // 渲染页面
//本地存储数据
window.localStorage.setItem('cartList', JSON.stringify(cartList)); // 将数组转换未字符串 进行本地存储
}
fun();
content.onclick = function (e) {
// console.log(1);
// 全选按钮
if (e.target.className == "quXun") { // 找到全选按钮 点击
// console.log(1);`
cartList.forEach(function (item) { // 遍历数组 拿到每一个数据
item.status = e.target.checked; // 使拿到 选中
})
fun(); //调用函数 渲染页面
}
// 单选按钮
if (e.target.className == "danXun") {
console.log(1);
cartList.forEach(function (item) {
if (item.id == e.target.dataset.id) {
item.status = !item.status; // 点击时status为false 点击后就变为true => 点击后是否被选 取决于点击前是否被选 取反
}
})
fun();
}
// 数量减
if (e.target.className == "jing") { //通过判断类名 找到减去标签
cartList.forEach(function (item) { // 遍历数组拿到每一个数据
// console.log(item);
if (item.id == e.target.dataset.id && item.number >= 2) { // 判断是否id相同 相同就可以减 减到1时按钮禁止
item.number--; // 数量自减
}
})
fun(); // 调用函数渲染页面
}
// 数量加
if (e.target.className == "jia") {
// console.log(1);
cartList.forEach(function (item) {
if (item.id == e.target.dataset.id && item.number < item.total) { // 不会一直加 达到库存量后按钮禁用
item.number++; // 数量自加
}
})
fun(); // 调用函数渲染页面
}
//清空购物车
if (e.target.className == "clier") {
// console.log(1);
var b = confirm('您确定要清空吗?');
if (b) {
cartList = []; // 清空后无数据 => 将数组赋值为空数组
}
fun();
}
// 去结算
if (e.target.className == "jieSun") {
// console.log(1);
console.log(e.target.dataset.totalprice); // dataset-totalPrice: h5新增自定义属性 dataset.totalprice
}
//删除所有已选中
if (e.target.className == "del") {
// console.log(1);
var b = confirm('您确定要删除吗?');
if (b) {
cartList = cartList.filter(function (item) { //数组过滤
return !item.status; // 选中取反 => 选中的被过滤掉
})
}
fun();
}
// 删除某一项
if(e.target.className == "del1"){
// console.log(1)
var b = confirm('你确定要删除吗')
if(!b) return // 取消啥也不执行
cartList = cartList.filter(function(item){
return item.id != e.target.dataset.id; // 删除id相同的 同时利用h5新增属性 在点击按钮处添加动态id
})
fun(); // 调用函数渲染
}
}