案例描述

如图所示,通过点击加号或者减号按钮会自动计算小计的价格。逻辑非常简单。

在线展示:https://antmoe.gitee.io/project/2020/04/18/shop.html

实现过程

逻辑非常简单,获取值计算即可。

  1. 为两个按钮分别绑定事件
  2. 改变值
  3. 返回

代码实现

加号与减号逻辑几乎一样,以加号示例。

首先我们得HTML结构为

<table id="cart">
    <tr>
        <th><input type="checkbox" name="" id="checkall"> 全选</th>
        <th>商品</th>
        <th>单价</th>
        <th>数量</th>
        <th>小计</th>
        <th>操作</th>
    </tr>
    <tr>
        <td><input type="checkbox" name="check"></td>
        <td>【49元1件88元2件118元3件】富贵鸟春季新品长袖格子男 509灰色 XL</td>
        <td><span name="price">2599.00</span></td>
        <td>
            <button name="minus" disabled>-</button>
            <input type="text" name="count" value="1">
            <button name="add">+</button>
        </td>
        <td><span name="subtotal">2599.00</span></td>
        <td><a href="#" name="delete">删除</a></td>
    </tr>
    <tr>
        <td><input type="checkbox" name="check"></td>
        <td>【49元1件88元2件118元3件】富贵鸟春季新品长袖格子男 509灰色 XL</td>
        <td><span name="price">2599.00</span></td>
        <td>
            <button name="minus" disabled>-</button>
            <input type="text" name="count" value="1">
            <button name="add">+</button>
        </td>
        <td><span name="subtotal">2599.00</span></td>
        <td><a href="#" name="delete">删除</a></td>
    </tr>
    <tr>
        <td><input type="checkbox" name="check"></td>
        <td>【49元1件88元2件118元3件】富贵鸟春季新品长袖格子男 509灰色 XL</td>
        <td><span name="price">2599.00</span></td>
        <td>
            <button name="minus" disabled>-</button>
            <input type="text" name="count" value="1">
            <button name="add">+</button>
        </td>
        <td><span name="subtotal">2599.00</span></td>
        <td><a href="#" name="delete">删除</a></td>
    </tr>
</table>
  1. 应该找到每一个加号按钮,并分别为其绑定事件。并且我们需要知道用户到底点击的是哪一个按钮。

    // 获取所有加号按钮
    var addButtons = document.getElementsByName('add')
    for (var i = 0; i < addButtons.length; i++) {
        // 因为获取的按钮是一个集合,因此需要取出每一项来添加事件
        var addButton = addButtons[i]
        // 为每个按钮添加点击事件,传入参数event
        addButton.onclick = function (event) {}
    }
  2. 接下来要做的就是获取输入框,并改变其值

    // 获取当前点击的按钮
    var targetButton = event.target
    // 操作与之关联的input元素 (存在空白节点问题,所以需要连续向上取两次)
    var inputElement = targetButton.previousSibling.previousSibling
    // 获取数量(string类型需要转化为Number类型)
    var count = Number(inputElement.value)
    // 计算
    count += 1
    // 将值更新到页面
    inputElement.value = count
    // 获取减按钮(这里需要判断减按钮是否可以被点击)
    var minuButton = inputElement.previousSibling.previousSibling
    if (count > 1) {
        minuButton.removeAttribute('disabled')
    } else {
        minuButton.setAttribute('disabled', 'disabled')
    }
  3. 既然可以改变输入框内容了,那接下来就是要计算小计的价格了。

    // 通过当前点击的按钮获取父级节点
    var btnTdElement = targetButton.parentNode
    // 通过按钮的父级节点获取单价节点
    var priTdElement = btnTdElement.previousSibling.previousSibling
    // 获取单价
    var priceElement = priTdElement.childNodes[1]
    // 将单价转换为浮点型
    var price = parseFloat(priceElement.firstChild.nodeValue)
    // 计算总值
    var subtotal = price *= count
    // 判断是否有小数点,没有添加
    if (String(subtotal).indexOf('.') === -1) {
        subtotal = subtotal + '.00'
    }
    // 通过按钮的父级节点获取下一个兄弟元素即总价节点
    var subTdElement = btnTdElement.nextSibling.nextSibling
    // 获取总价
    var subtotalElement = subTdElement.childNodes[1]
    // 改变总价的文本
    subtotalElement.textContent = subtotal
  4. 主要功能都完成了,接下来就是细节了,即最前边的复选框和背景颜色

    // 通过按钮的父级节点获取父级节点
    var trElement = btnTdElement.parentNode
    // 通过上一步找到的tr元素节点 获取第一个子节点即复选框节点
    var checkTdElement = trElement.childNodes[1]
    // 获取复选框节点的input节点
    var checkboxElement = checkTdElement.firstChild
    // 设置值
    checkboxElement.setAttribute('checked', 'checked')
    // 将当前这一行的背景颜色修改 #fff4e8
    trElement.style.backgroundColor = '#fff4e8'
  5. 至于减按钮功能类似

    for (var i = 0; i < minusButtons.length; i++) {
        var minusButton = minusButtons[i]
        minusButton.onclick = function (event) {
            var targetButton = event.target
            // 操作与之关联的input元素
            var inputElement = targetButton.nextSibling.nextSibling
            console.log(inputElement)
            // 获取数量(string类型)
            var count = Number(inputElement.value)
            // 计算
            count -= 1
            // 将值更新到页面
            inputElement.value = count
            // 计算小计
            var btnTdElement = targetButton.parentNode
            var priTdElement = btnTdElement.previousSibling.previousSibling
            var priceElement = priTdElement.childNodes[1]
            var price = parseFloat(priceElement.firstChild.nodeValue)
            var subtotal = price *= count
            if (String(subtotal).indexOf('.') === -1) {
                subtotal = subtotal + '.00'
            }
            var subTdElement = btnTdElement.nextSibling.nextSibling
            var subtotalElement = subTdElement.childNodes[1]
            subtotalElement.textContent = subtotal
            // console.log(price)
    
            // 操作减按钮
            if (count <= 1) {
                targetButton.setAttribute('disabled', 'disabled')
                // 复选框
                var trElement = btnTdElement.parentNode
                var checkTdElement = trElement.childNodes[1]
                var checkboxElement = checkTdElement.firstChild
                checkboxElement.removeAttribute('checked')
                // 将当前这一行的背景颜色修改 #fff4e8
                trElement.style.backgroundColor = 'white'
            }
    
        }
    }
  6. 删除按钮

    完成了加减后,删除按钮就很简单了。但是需要注意几点:

    ①删除的是当前所在按钮的父级,也就是tr标签

    ②删除后需要将上方的总数修改-1

    ③就是a标签的跳转

    // 删除按钮
    var delButtons = document.getElementsByName("delete")
    for (var i = 0; i < delButtons.length; i++) {
        var delButton = delButtons[i]
        delButton.onclick = function (event) {
            var targetButton = event.target
            var currentTrElement = targetButton.parentNode.parentNode
            var parentElement = currentTrElement.parentNode
            parentElement.removeChild(currentTrElement)
    		//修改上方总数量
            var numberElement = document.getElementById('number')
            var number = parseInt(numberElement.textContent)
            number -= 1
            numberElement.textContent = number
            /*
                    阻止a标签跳转
                    1. 通过调用调用 preventDefault() 
                    2. 时间的处理函数 return 语句 -> return false
                    */
            event.preventDefault()
        }
    }
  7. 全选

    tip:判断复选框的checked属性即可知道是否被选择。

    var checkall = document.getElementById("checkall")
    checkall.onclick = function () {
        console.log(1)
        console.log(checkall.checked)
        var checkElements = document.getElementsByName("check")
        var cart = document.getElementById('cart')
        var trElements = cart.getElementsByTagName('tr')
        if (checkall.checked) {
            for (var i = 0; i < checkElements.length; i++) {
                var checkElement = checkElements[i]
                checkElement.setAttribute("checked", "checked")
            }
            for (var i = 1; i < trElements.length; i++) {
                var trElement = trElements[i]
                trElement.style.backgroundColor = '#fff4e8'
            }
    
        } else {
            for (var i = 0; i < checkElements.length; i++) {
                var checkElement = checkElements[i]
                checkElement.removeAttribute('checked')
            }
            for (var i = 1; i < trElements.length; i++) {
                var trElement = trElements[i]
                trElement.style.backgroundColor = 'transparent'
            }
        }
    
    }

完整代码

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

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>购物车案例</title>
        <style>
            * {
                box-sizing: border-box;
            }

            .cart-container {
                margin: 100px auto;
                width: 990px;
            }

            #title {
                width: 100px;
                color: #c81623;
                padding: 10px 0px;
                margin: 0;
                border-bottom: 1px solid #c81623;
            }

            #cart {
                width: 990px;
                border: 1px solid #d9d9d9;
                border-collapse: collapse;
            }

            #cart th,
            #cart td {
                height: 80px;
                border-bottom: 1px solid #d9d9d9;
                text-align: center;

            }

            #cart th {
                background: #d9d9d9;
            }

            #cart td:nth-of-type(1) {
                width: 60px;
                text-align: center;
            }

            #cart td:nth-of-type(2) {
                width: 400px;
            }

            #cart td:nth-of-type(3) {
                width: 80px;
                text-align: right;
            }

            #cart td:nth-of-type(4) {
                width: 250px;
                padding: 0 80px;
            }

            #cart td:nth-of-type(5) {
                width: 80px;
                text-align: right;
            }

            #cart td:nth-of-type(6) {
                /* width: 80px; */
                text-align: center;
            }

            #cart td:nth-of-type(4) button,
            #cart td:nth-of-type(4) input {
                display: block;
                float: left;
                height: 25px;
                border: 1px solid #d9d9d9;
            }

            #cart td:nth-of-type(4) button {
                width: 20px;
                background-color: #fff;
            }

            #cart td:nth-of-type(4) input {
                padding: 0;
                border-width: 1px;
                border-left: none;
                border-right: none;
                width: 50px;
                outline: none;
                text-align: center;
            }

            #cart td:nth-of-type(4) input:focus {
                background-color: #f1f1f1;
            }

            #cart td a {
                text-decoration: none;
                color: #333333;
            }

            #cart td a:hover {
                color: #c81623;
            }
        </style>
    </head>

    <body>
        <div class="cart-container">
            <!-- 购物车标题+商品数量 -->
            <h3 id="title">全部商品<span id="number">3</span></h3>
            <!-- 购物车表格 -->
            <table id="cart">
                <tr>
                    <th><input type="checkbox" name="" id="checkall"> 全选</th>
                    <th>商品</th>
                    <th>单价</th>
                    <th>数量</th>
                    <th>小计</th>
                    <th>操作</th>
                </tr>
                <tr>
                    <td><input type="checkbox" name="check"></td>
                    <td>【49元1件88元2件118元3件】富贵鸟春季新品长袖格子男 509灰色 XL</td>
                    <td><span name="price">2599.00</span></td>
                    <td>
                        <button name="minus" disabled>-</button>
                        <input type="text" name="count" value="1">
                        <button name="add">+</button>
                    </td>
                    <td><span name="subtotal">2599.00</span></td>
                    <td><a href="#" name="delete">删除</a></td>
                </tr>
                <tr>
                    <td><input type="checkbox" name="check"></td>
                    <td>【49元1件88元2件118元3件】富贵鸟春季新品长袖格子男 509灰色 XL</td>
                    <td><span name="price">2599.00</span></td>
                    <td>
                        <button name="minus" disabled>-</button>
                        <input type="text" name="count" value="1">
                        <button name="add">+</button>
                    </td>
                    <td><span name="subtotal">2599.00</span></td>
                    <td><a href="#" name="delete">删除</a></td>
                </tr>
                <tr>
                    <td><input type="checkbox" name="check"></td>
                    <td>【49元1件88元2件118元3件】富贵鸟春季新品长袖格子男 509灰色 XL</td>
                    <td><span name="price">2599.00</span></td>
                    <td>
                        <button name="minus" disabled>-</button>
                        <input type="text" name="count" value="1">
                        <button name="add">+</button>
                    </td>
                    <td><span name="subtotal">2599.00</span></td>
                    <td><a href="#" name="delete">删除</a></td>
                </tr>
            </table>
        </div>
        <!-- 结算 -->
        <script>
            // 获取到购物车中所有加按钮
            var addButtons = document.getElementsByName('add')
            var minusButtons = document.getElementsByName('minus')
            console.log(minusButtons)
            // 事件的绑定 -> 每次只能绑定一个元素

            for (var i = 0; i < addButtons.length; i++) {
                var addButton = addButtons[i]
                // 绑定鼠标事件
                // 修改数量
                addButton.onclick = function (event) {
                    console.log('click')
                    /*
                    通过event对象获取用户点击的是哪个按钮
                    * 绑定事件的元素 -> 所有的<botton name='add'>+</botton>
                    * 触发事件的元素 -> 只能有一个
                */
                    // console.log(event.currentTarget, event.target, this)
                    var targetButton = event.target
                    // 操作与之关联的input元素
                    var inputElement = targetButton.previousSibling.previousSibling
                    // console.log(inputElement)
                    // 获取数量(string类型)
                    var count = Number(inputElement.value)
                    // 计算
                    count += 1
                    // 将值更新到页面
                    inputElement.value = count
                    // 操作与之关联的减按钮
                    var minuButton = inputElement.previousSibling.previousSibling
                    if (count > 1) {
                        minuButton.removeAttribute('disabled')
                    } else {
                        minuButton.setAttribute('disabled', 'disabled')
                    }
                    // 更新与之关联的小计
                    // 获取单价
                    var btnTdElement = targetButton.parentNode
                    var priTdElement = btnTdElement.previousSibling.previousSibling

                    var priceElement = priTdElement.childNodes[1]
                    var price = parseFloat(priceElement.firstChild.nodeValue)
                    var subtotal = price *= count
                    if (String(subtotal).indexOf('.') === -1) {
                        subtotal = subtotal + '.00'
                    }
                    var subTdElement = btnTdElement.nextSibling.nextSibling
                    var subtotalElement = subTdElement.childNodes[1]
                    subtotalElement.textContent = subtotal
                    // console.log(price)

                    // 复选框
                    var trElement = btnTdElement.parentNode
                    var checkTdElement = trElement.childNodes[1]
                    var checkboxElement = checkTdElement.firstChild
                    checkboxElement.setAttribute('checked', 'checked')

                    // 将当前这一行的背景颜色修改 #fff4e8
                    trElement.style.backgroundColor = '#fff4e8'
                }
            }
            for (var i = 0; i < minusButtons.length; i++) {
                var minusButton = minusButtons[i]
                minusButton.onclick = function (event) {
                    var targetButton = event.target
                    // 操作与之关联的input元素
                    var inputElement = targetButton.nextSibling.nextSibling
                    console.log(inputElement)
                    // 获取数量(string类型)
                    var count = Number(inputElement.value)
                    // 计算
                    count -= 1
                    // 将值更新到页面
                    inputElement.value = count


                    // 计算小计
                    var btnTdElement = targetButton.parentNode
                    var priTdElement = btnTdElement.previousSibling.previousSibling

                    var priceElement = priTdElement.childNodes[1]
                    var price = parseFloat(priceElement.firstChild.nodeValue)
                    var subtotal = price *= count
                    if (String(subtotal).indexOf('.') === -1) {
                        subtotal = subtotal + '.00'
                    }
                    var subTdElement = btnTdElement.nextSibling.nextSibling
                    var subtotalElement = subTdElement.childNodes[1]
                    subtotalElement.textContent = subtotal
                    // console.log(price)

                    // 操作减按钮
                    if (count <= 1) {
                        targetButton.setAttribute('disabled', 'disabled')
                        // 复选框
                        var trElement = btnTdElement.parentNode
                        var checkTdElement = trElement.childNodes[1]
                        var checkboxElement = checkTdElement.firstChild
                        checkboxElement.removeAttribute('checked')
                        // 将当前这一行的背景颜色修改 #fff4e8
                        trElement.style.backgroundColor = 'white'
                    }

                }
            }
            // 删除按钮
            var delButtons = document.getElementsByName("delete")
            for (var i = 0; i < delButtons.length; i++) {
                var delButton = delButtons[i]
                delButton.onclick = function (event) {
                    var targetButton = event.target

                    var currentTrElement = targetButton.parentNode.parentNode
                    var parentElement = currentTrElement.parentNode
                    parentElement.removeChild(currentTrElement)

                    var numberElement = document.getElementById('number')
                    var number = parseInt(numberElement.textContent)
                    number -= 1
                    numberElement.textContent = number
                    /*
                阻止a标签跳转
                1. 通过调用调用 preventDefault() 
                2. 时间的处理函数 return 语句 -> return false
                */
                    event.preventDefault()
                }
            }

            // 全选
            var checkall = document.getElementById("checkall")
            checkall.onclick = function () {
                console.log(1)
                console.log(checkall.checked)
                var checkElements = document.getElementsByName("check")
                var cart = document.getElementById('cart')
                var trElements = cart.getElementsByTagName('tr')
                if (checkall.checked) {
                    for (var i = 0; i < checkElements.length; i++) {
                        var checkElement = checkElements[i]
                        checkElement.setAttribute("checked", "checked")
                    }
                    for (var i = 1; i < trElements.length; i++) {
                        var trElement = trElements[i]
                        trElement.style.backgroundColor = '#fff4e8'
                    }

                } else {
                    for (var i = 0; i < checkElements.length; i++) {
                        var checkElement = checkElements[i]
                        checkElement.removeAttribute('checked')
                    }
                    for (var i = 1; i < trElements.length; i++) {
                        var trElement = trElements[i]
                        trElement.style.backgroundColor = 'transparent'
                    }
                }

            }

        </script>
    </body>

</html>