购物车案例
- html基础结构
<div class="header">页面顶部</div>
<div class="content">
<div class="top">
<input type="checkbox"> 全选
</div>
<ul>
</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>
<script src="./index.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;
}
- 通过外链引入的js代码
/**
* 数组数据分析
* 1. id: 数据的唯一值
* 2. status: true代表该商品被选中, false则为没被选中
* 3. pic: 图片地址
* 4. name: 商品名
* 5. price: 价格
* 6. number: 商品收藏数量
* 7. total: 库存
*
* 0. 使用数据驱动视图
* 是一种新的开发思想, 目前主流框架都是使用这种思想
* 我们操作的时候只关注数据, 任何修改都是修改数据, 然后重新渲染视图
* 1. 通过数据重构页面
* 1.1 准备一个渲染函数
* 1.2 首次打开页面的时候, 直接调用渲染函数
* 2. 全选
* 2.1 当你点击了全选按钮, 然后到数据中, 将数组中所有对象的选中状态更改为 true 或者 false
* 2.2 重新渲染
* 3. 清空购物车
* 3.1 将数组清空
* 3.2 重新渲染
* 4. 结算 (将所选择商品总价计算出后打印到控制台)
* 4.1 找出所有被选中的商品, 计算这些商品总价之和, 打印到控制台
* 5. 删除已选中
* 5.1 找出数组中选中状态为 true, 然后将它们删掉 (将数组中选中状态为 false 的 留下)
* 5.2 重新渲染
* 6. 商品数量调整
* 6.1 找到数组中对应的这个商品, 将他的收藏数量调整
* 6.2 重新渲染
* 7. 选中商品
* 7.1 找到数组中对应的这个商品, 将他的状态更改为选中
* 7.2 重新渲染
* 8. 删除某一项
* 8.1 找到数组中对应的这个商品, 将他删除 (将数组中不是这个商品的留下)
* 8.2 重新渲染
* 9. 数据持久化 (浏览器关闭, 数据能保存)
* 9.1 本地存储
*/
// 0. 模拟从后端请求回来的商品数据, 不认识就找人要接口文档
var cartList =JSON.parse(window.localStorage.getItem('cartList'))|| [
// 当从后端拿过来数据时,会出现JSON格式的的数据,这个数据时从该服务拿过来的
// 这时会储存浏览器本地储存中,会将从本地储存中拿到数据
// 每一个对象就是一个购物车内容的数据
{
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,
},
];
// console.log(cartList); 得到三组数据
// 要对里面的数据进行改变,即对里面进行点击时进行进行相关操作
// 因为文档中有跟多元素需要点击,考虑用给 "事件委托" 即 操作父亲就能里面的要操作的东西进行操作
// 0. 获取标签
var content = document.querySelector(".content");
// 0. 准备变量
// 1. 通过数据重构页面, 准备一个渲染函数
function getFn() {
// 准备未点击全选时,选中商品数量未0的变量
var selectItem = 0;
// 当我点击全选时,即所有的商品status: true,用遍历
var selectItemNum =0;
// 准备存储选中商品收藏的总数量
var totalNum = 0; // 存储选中商品的总价格
// 因中间内容和需要数据进行操作
// 暂时对外面的数据进行设定
// 对里面的数据进行操作, 并让他显示出来
cartList.forEach(function(item){
// 遍历数组里面的数据
if(item.status){
// 当里面的status 为 true 时,表示 该选项已经选了,
selectItem++;
// 当status: true时,则选中商品数量+1
selectItemNum += item.number;
// 此时商品的总数量也会改变 即 + 里面项number的值
totalNum += item.price * item.number;
// 随之 总价格也会变化 为 数组 里面项的price * 里面项number的值
}
});
var strHtml = `
<div class="top">
<input type="checkbox" class="select_all"
${selectItem === cartList.length && cartList.length !== 0 ? "checked" : ""}> 全选
</div>
<ul>`;
// 中间内容不变, 要么 商品选中的数量 对多的时候 (即:全部选了),
// 要不 商品一个都不选 即为 空
strHtml += cartList.reduce(function (prev, item) {
// 每次遍历都呈现出来,这样就都呈现出来了
return (
prev +
`<li>
<div class="status">
<input class="status_item" 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}
</div>
<div class="number">
<button class="sbs" data-id="${item.id}">-</button>
<input type="text" value="${item.number}">
<button class="add" data-id="${item.id}">+</button>
</div>
<div class="sub">
¥ ${(item.price * item.number).toFixed(2)}
</div>
<div class="destory">
<button class="del" data-id="${item.id}"}>删除</button>
</div>
</li>`
);
}, "");
// 将里面的值,用数组里面的数据表示出来
strHtml += `</ul>
<div class="bottom">
<div class="totalNum">
总件数 :${selectItemNum}
</div>
<div class="btns">
<button class="clear">清空购物车</button>
<button class="go_pay" data-price="${totalNum}">去结算</button>
<button class="del_item">删除所有已选中</button>
</div>
<div class="totalPrice">
总价格 : ¥ <span>${totalNum.toFixed(2)}</span>
</div>
</div>`;
// 字符串处理完毕, 放到页面中
content.innerHTML = strHtml;
// 将遍历的所有数据放到父级里面
// 每次修改数据时都会进行本地存储
window.localStorage.setItem('cartList', JSON.stringify(cartList))
}
// 首次打开页面直接调用函数
getFn();
content.onclick=function(e){
// 1.全选
/**
* e.target 表示你点击的时哪一个标签, className 是拿到这个标签的类名, 如果类名 === select_all 代表点击的是全选按钮
*/
if(e.target.className === "select_all"){
// 将数组捏所有数据的选中状态更改
// 此时找到全选框
cartList.forEach(function (item) {
// 对这个 数组进行遍历
item.status = e.target.checked;
// console.log(e.target.checked);//true
// 当选中了之后,标签里面被选中了
// 当前分支执行, e.target一定是那个全选按钮, 然后 checked 表示当前这个按钮有没有被选中
// 当点击全选择时,每个项都选择了(即status为true)等于说全选了
})
// 重新渲染
getFn();
}
// 3.清空购物车
if(e.target.className === "clear"){
// 找到清空购物车按钮后
// if(confirm('请问你确定要删除吗')){
// 3.1 清空购物车数据
// cartList = [];
// 进行清空里面的数据
// 重新渲染
// getFn()
// }
if(!confirm("请问您是否删除"))return
// 防止手滑无意中删除
// 3.1 清空购物车数据
cartList = [];
// 重新渲染
getFn()
}
// 运用到事件委托当点击子级时,父级会受其影响
// 4.结算
if(e.target.className === "go_pay"){
// 找到结算按钮后 返回结算的值
console.log(e.target.dataset.price);
// 利用 data-price="${totalNum}" 添加一个
// 找到结算按钮
}
// 5. 删除已选中
if (e.target.className === "del_item") {
// 5.0 安全校验, 防止手滑
if(!confirm("请问您是否删除"))return;
// 5.1 将这个数组内的 选中状态为 true 都删掉
// 换句话说: 只留下 选中状态为 false 的
cartList = cartList.filter(function (item) {
// return item.status === false
return !item.status;
// 过滤得到不选中的数据
});
// console.log(cartList);
// 5.2 重新渲染
getFn();
}
// 6.商品数量调整
// 减少
if(e.target.className === "sbs"){
// console.log(e.target); //<button class ="sbs">-</button>
// cartList.forEach(function (item) {
// // 对cartList里面的项进行遍历
// //对 尽心该操作的项进行操作
// if (item.id === e.target.dataset.id - 0){
// data-id=${item.id} ???
// // 找到哪个就进行之后的操作
// if (item.number !== 1){
// item.number--
// } else {
// alert("商品收藏数量最小为 1")
// }
// }
// })
var i = cartList.find(function (item){
// 查找每一个数据并且能够找到对应的项
return item.id === e.target.dataset.id - 0
})
if(i.number === 1)return alert("商品收藏数量最小为 1");
// 数量最少为1 不能低于1 ,否则出提示 "商品收藏数量最小为 1"
// 数量减小
i.number--;
// 5.2 重新渲染
getFn()
}
if(e.target.className === "add"){
// 找到这个标签
// 增加
var i = cartList.find(function(item){
// 查找每一个数据并且能够找到对应的项
return item.id === e.target.dataset.id - 0;
});
if (i.number === i.total) return alert("商品收藏数量不能超过库存");
i.number++;
// 5.2 重新渲染
getFn();
}
// 7. 选中商品
if(e.target.className === 'status_item'){
// 找到这个商品,
var i = cartList.find(function (item){
// 每个商品都可能被选中,为了确定改选中那个选项
return item.id === e.target.dataset.id - 0;
})
i.status = !i.status;
// 如果 选中时则status 为 true
// 如果不选时 则 status 为 false
getFn()
}
// 8.删除某一项
if(e.target.className === 'del'){
//找到项要删除的这件物品
if(confirm('你确定删除吗')){
//
cartList = cartList.filter(function (item) {
// 查找每一个数据并且能够找到对应的项
return item.id !== e.target.dataset.id - 0;
//
});
getFn();
}
// 当我过滤某个东西,返回满足条件的值
// console.log(i);
}
}