简易购物车

89 阅读5分钟

html

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Document</title>
	<link rel="stylesheet" href="./index.css">
</head>

<body>

	<div class="header">页面顶部</div>
	<div class="content">
		
			
		
	</div>
	<div class="footer">页面底部</div>

	<script src="./index.js"></script>
</body>

</html>

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")) || [
    // 每一个对象就是一个购物车内容的数据
    {
        id: 111234,
        status: true,
        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: true,
        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: 3,
    },
    {
        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,
    },
];

// 0. 获取标签
var content = document.querySelector(".content");
// 0. 准备变量

// 1. 通过数据重构页面, 准备一个渲染函数
function myFn() {
    var selectItem = 0; // 存储选中商品的数量
    var selectItemNum = 0; // 存储选中商品收藏的总数量
    var totalNum = 0; // 存储选中商品的总价格
    cartList.forEach(function (item) {
        if (item.status) {
            // 如果当前分支能够执行, 说明当前的 item 为 选中的状态
            selectItem++;
            selectItemNum += item.number;
            totalNum += item.price * item.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 data-id="${
                        item.id
                    }" class="status_item" 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="subs" 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 data-id="${item.id}" class="del">删除</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));
}

// 首次打开页面直接调用函数
myFn();

// 利用事件委托, 将事件全都委托给共同的祖先级
content.onclick = function (e) {
    // 2. 全选
    if (e.target.className === "select_all") {
        // 2.1 将数组内所有数据的选中状态更改
        cartList.forEach(function (item) {
            item.status = e.target.checked;
        });
        // 2.2 重新渲染
        myFn();
    }

    // 3. 清空购物车
    if (e.target.className === "clear") {
        if (!confirm("请问您是否删除")) return;
        // 3.1 清空购物车数据
        cartList = [];
        // 3.2 重新渲染
        myFn();

        // if (confirm('请问您是否删除')) {
        //     // 3.1 清空购物车数据
        //     cartList = []
        //     // 3.2 重新渲染
        //     myFn()
        // }
    }

    // 4. 结算
    if (e.target.className === "go_pay") {
        console.log(e.target.dataset.price);
    }

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

        // 5.2 重新渲染
        myFn();
    }

    // 6. 调整商品数量
    if (e.target.className === "subs") {
        // 减少
        // 6.1 在数组中找到对应的商品, 然后将他的收藏数量 - 1
        // cartList.forEach(function (item) {
        //     if (item.id === e.target.dataset.id - 0) {
        //         if (item.number !== 1) {
        //             item.number--
        //         }
        //     }
        // })
        var i = cartList.find(function (item) {
            return item.id === e.target.dataset.id - 0;
        });
        if (i.number === 1) return alert("商品收藏数量最小为 1");
        i.number--;

        // 6.2 重新渲染
        myFn();
    }

    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++;

        // 重新渲染
        myFn();
    }

    // 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;

        // 重新渲染
        myFn();
    }

    // 8. 删除某一项
    if (e.target.className === "del") {
        if (!confirm("请问您是否删除")) return;
        // 在数组中找到这个对象, 然后将他删除       (将数组中 id 不等于它的留下)
        cartList = cartList.filter(function (item) {
            return item.id !== e.target.dataset.id - 0;
        });

        myFn();
    }
};