JS购物车案例

128 阅读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 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>
    <script src="./index2.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:库存
 * 
 * 完成购物车的思想:   数据驱动视图
 *      套路:
 *          => 查询数据,渲染到页面
 *          => 增删改:找到源数据。然后对涿数据做修改,修改完成,重新渲染页面
 * 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 本地存储 localStorage
 * 
 * 
 * 总结:
 *      1.准备一个渲染函数
 *      2.在首次打开页面的时候,调用一次渲染函数
 *      3.在各种事件触发之后,重新调用渲染函数
 * */

    // 0. 模拟从后端请求回来的商品数据
    // console.log('第一次打开页面的 本地存储的值: ', 
    JSON.parse(window.localStorage.getItem("cartList")))
    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: 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: true,
        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')

// 1.准备一个渲染函数
function bindHtml() {
    var selectItem = 0 //存储选中商品的数量
    var selectTotalNum = 0 //存储选中商品的总件数
    var totalPrice = 0 // 存储选中商品的总价
    cartList.forEach(function(item) { //item选中的商品
        if(item.status) {
            selectItem ++ //forEach循环结束之后,找到了商品中被选中的商品数量
            selectTotalNum += item.number //forEach循环结束之后,被选中商品的收藏数量全都累加到了这个变量中
            totalPrice += item.number * item.price //forEach 循环结束之后,被选中商品的总价就全部累加到了这个变量中
        }
    })
    // console.log('我渲染页面了')
    
    // 1.1准备一个我们需要的字符串
    var str = `
    <div class="top">
        <input type="checkbox" class="select_all" ${selectItem === cartList.length ? 'checked' : ''}> 全选
    </div><ul>`;
    cartList.forEach(function(item) {
        str += `<li>
        <div class="status">
            <input type="checkbox" data-id="${item.id}" class="item" ${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="sub_btn" data-id="${item.id}">-</button>
            <input type="text" value="${item.number}">
            <button class="add_btn" data-id="${item.id}">+</button>
        </div>
        <div class="sub">
            ¥ ${(item.price * item.number).toFixed(2)}
        </div>
        <div class="destory">
            <button class="del_item" data-id="${item.id}">删除</button>
        </div>
    </li>`
    });
    str += `</ul>
    <div class="bottom">
        <div class="totalNum">
            总件数 : ${selectTotalNum}
        </div>
        <div class="btns">
            <button class="clear">清空购物车</button>
            <button class="go_pay" data-totalPrice="${totalPrice}">去结算</button>
            <button class="del">删除所有已选中</button>
        </div>
        <div class="totalPrice">
            总价格 : ¥ <span>${totalPrice.toFixed(2)}</span>
        </div>
    </div>`

    /**
    * JSON.stringify(数据)   将数据转换为JSON格式的字符串  但本质上还是一个字符串
    * JSON.parse(JSON格式的字符串)   将JSON格式的字符串,转换为原本的数据类型
    * */ 
    // 1.2将我们处理完毕的字符串插入到页面中
    content.innerHTML = str
    // 将数据存储至localStorage
    window.localStorage.setItem("cartList", JSON.stringify(cartList))
}

// 2.首次打开页面的时候 调用一次 渲染函数
bindHtml()

// 3.在各种事件触发之后,重新调用渲染函数; 利用事件冒泡将所有的事件委托给统一的父级
content.onclick = function (e) {
    // console.log(e.target)
    // 3.1全选功能
    if(e.target.className === 'select_all') {
        // console.log('点击了全选按钮')
        // e.target.checked  能够得到当前这个全选按钮的选中状态 true:选中  false:未选中
        // console.log(e.target.checked)
        cartList.forEach(function(item) {
            item.status = e.target.checked //控制是否选中按钮
        })
        // console.log(cartList)
        bindHtml() //重新渲染页面
    }
    // 3.2清空购物车
    if(e.target.className === 'clear') {
        // console.log('清空购物车')
        var boo = confirm('请问您确定清空吗?点击确定清空购物车')
        if(boo) {
            cartList = []
            bindHtml()
        }
    }
    // 3.3计算商品总价
    if(e.target.className === 'go_pay') {
        // console.log('计算商品总价,去结算')
        console.log(e.target.dataset.totalprice)
    }

    // 3.4删除对应项
    if(e.target.className === 'del_item') {
        // console.log('删除这一项')
        // console.log(e.target.dataset.id)
        cartList = cartList.filter(function(item) {
            return item.id != e.target.dataset.id //过滤
        })
        bindHtml()
    }
    // 3.5删除已选中
    if(e.target.className === 'del') {
        // console.log('删除已选中')
        cartList = cartList.filter(function(item) {
            return item.status === false
        })
        bindHtml()
    }
    // 3.6.1减少商品数量
    if(e.target.className === 'sub_btn') {
        // console.log('商品数量-1')
        // console.log(e.target.dataset.id)
        cartList.forEach(function(item) {
            if(item.id == e.target.dataset.id && item.number >= 2) {
                item.number--
            }
        })
        bindHtml()
    }
    // 3.6.2增加商品数量
    if(e.target.className === 'add_btn') {
        // console.log('商品数量+1')
        // console.log(e.target.dataset.id)
        cartList.forEach(function(item) {
            if(item.id == e.target.dataset.id && item.number < item.total) {
                item.number++
            }
        })
        bindHtml()
    }
    // 3.7选种商品
    if(e.target.className == 'item') {
        // console.log(e.target.dataset.id)
        cartList.forEach(function(item) {
            if(item.id == e.target.dataset.id) {
                item.status = !item.status
            }
        })
        bindHtml()
    }
}