购物车案例

207 阅读6分钟

购物车案例

  • 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);
}
}