jquery练习——购物车

这篇博客总结了作者在实现jQuery购物车功能时的学习经历,包括动态添加商品、全选、复选框、数量增减、文本框变化、删除操作的业务逻辑。通过实践,作者认识到事件处理、代码复用和事件代理的重要性,并分享了关于val()、attr()、prop()、index()和each()方法的理解。

购物车练习总结

初学练习,收货颇多。两个方便,一部分是技术知识上的,一部分是开发思路上的。

整个练习的业务逻辑包括:

1.动态的通过按钮添加商品,商品名价格等随机产生
2.实现全选按钮点击事件(反选取消全选)
3.实现复选框点击事件
4.实现数量加减按钮点击事件
5.实现文本框数量改变事件
6.实现删除操作

商品内容包括如下:

这里写图片描述

在开始写的时候并没有做任何分析,仅仅是用一种车到山前必有路的方式一点一点的解决,想到什么写什么,完全没有联系各个事件可能存在的关系。

比如说实现文本框内容的改变,也是因为首次写,虽然查过change事件,但是还是用了不是最好的focus和blur事件来处理,在处理时知道会引起总计的改变,但是可能没有考虑到如果在选中的情况下总价也会改变,而事后想起才再添加功能,
在说数量加减点击事件,没有思考和文本框的联系,就是用完全正常的思路,点击后会引起文本框数值的改变,合计改变,可能改变的总价,实际上这里完全可以在点击事件
中改变文本框的值后,在模拟文本框的change事件,可以大大简化代码,并且更加合理。

虽然最后写完了,虽然练习了jquerr的dom操作的选择器,但是最后的代码冗杂,不够简洁。

然后在完成的结果上加上老师的思路对其在从头分析。

首先分析各个事件的业务逻辑:

1.按钮点击添加商品事件,点击后需要判断全选按钮是否是全选,如果全选,全选按钮取消选中。
2.全选按钮点击事件,点击后所有的商品复选框和全选框保持一致的选中状态。同时这里全选状态的改变会引起总价的改变。
3.复选框的点击事件会引起总价的改变,同时可能引起全选框状态的改变。
4.数量加减会引起文本框值的变化和总计的变化,同时可能引起总价的变化。同时需要注意这里文本框值的限制必须大于0.
5.文本框数量的变化会引起总计的变化,可能会引起总价的变化,同时考虑其值的限制必须大于0.
6.删除操作直接的就是删除该商品行,同时需要考虑可能引起总价的变化,和全选框的变化。

代码实现逻辑:

从上面的业务逻辑中可知很多操作都和总价有关,因此实现一个计算总价的函数。总价函数根据商品选中与否和商品总计来计算。

1.按钮点击添加商品。考虑实现动态添加商品,即给按钮添加点击事件。这里需要考虑新增的商品html元素的事件问题。有三种方法:
一、用给定的model ul来clone(true),首先给modle ul加好事件,每次clone(),给定true参数也会clone到绑定的事件。
二、处理事件利用事件代理来解决。给添加的这个商品元素的父元素增加对添加元素的事件代理。只需要先给其父元素绑定代理事件,然后添加元素节点即可。
三、每次增加商品ul节点时,给这个节点绑定每个事件。
选用一种方法来实现动态增加商品节点。这里采用第一种方法,克隆model ul对象后,产生随机商品替换价格等。同时要考虑到全选框的状态。

2.文本框值的改变。
开始思路:在实现这个问题的时候因为不熟悉表单操作,费了很大劲(因为这里不知道prop()和attr(“value”)的区别的使用方法
,也因此对prop()和attr()的使用比较熟悉了)。首先考虑的是获取到改变前的值,可以用focus函数获得,然后就是在blur事件中获得改变后的值,然后便是
实现改变合计,如果当前商品被选中的话改变总价。在这里就完了。写的代码因选择器使用不熟写的也很冗长。其实后面没有考虑到其实用不着
改变前的值,并且还需要对改变后的值做判断,如果为0为负数怎么处理。
老师思路:使用change函数,获得改变后的值后,对值判断后进行对应的处理,合法值改变合计,不合法值0表示删除,负数重新设置值为1,改变合计。
最后改变总价,利用计算总价函数

3.加减数量按钮
开始思路:
点击后,先将文本框内容加1,在改变合计,如果商品选中改变总价。代码冗长。(回想起来,代码中存在很多总价和总计的计算)
老师思路:改变文本框的值,然后出发文本框的change事件(change事件中包括了合计总价的处理)。

4.复选框
开始思路:判断状态,实现反选,改变总价(又重复计算总价代码).同时判断是否改变全选框的状态。
老师思路:不用判断,直接计算总价,调用计算总价函数,判断是否改变全选框状态,

5.全选按钮
开始思路:判断全选框状态,根据不同状态分别重设商品复选框状态,改变总价。
老师思路:获取全选框的状态,用each实现将每一个商品的状态设置同全选框一样的状态,调用总价计算函数,

6.删除操作
开始思路:删除当前商品,计算总价。
老师思路:删除当前商品,计算总价。

代码思想上的收获:1.重复代码提取出来。2.写代码前先思考清楚。3.思考不同事件间可能的联系。

技术知识上的收获:1.事件委托。2.关于val()和attr() 3.关于prop()函数和attr()函数 4.关于索引的index()函数 5.each()遍历

1。关于val()函数和attr(“value”)问题
在给text文本框添加事件使用val()发现不能改变元素value属性值,而用attr()不能让文本框内容改变,因此关于value的操作可能要同时用两个。前者用来改变文本框的值,后者用来设置属性
val()方法
    val()主要是用来处理表单元素的值的,如input、select等
    只能使用在表单元素上      
二者区别
    val()函数可以获得动态的text文本框的值,而attr("value")只能获得html元素中设置的value属性值,而这个值除非用attr("value",somevlaue)重新设置,它的值时不变的。
2.关于复选框的checked属性和prop()函数和attr()
使用时发现prop()无法设置checked的值,而attr()可以。使用prop()函数获得的返回值是true或者false;而attr("checked")返回的是“checked”或者undifined
prop()方法
    关于什么时候使用prop()方法
        如果添加属性名称该属性就会生效应该使用prop()
        如果只存在true和false两个属性值应该使用prop(),如checked,disabled等
    返回值为true和false  
二者区别
    prop()获得的是节点DOM对象的属性值,这个值是随着复选框的选中或者不选而改变。而attr()获得是html元素设置的checked值,不会随页面中对复选框的操作而改变值,只能用attr("checked")来重新设置。当html元素没有设置checked属性时,前者返回false,后者返回undefined。当选中时前者返回的是true,后者返回的是false、
3.获取元素在选取的元素集合中的下标
使用index()方法
    注意有参和无参时的结果
    可以传递的参数包括选择器或者DOM对象或者jquery对象或者传递一组jquery对象或者不传参数
    实例
        $('li').index(document.getElementById('bar')); //1,传递一个DOM对象,返回这个对象在原先集合中的索引位置
        $('li').index($('#bar')); //1,传递一个jQuery对象
        $('li').index($('li:gt(0)')); //1,传递一组jQuery对象,返回这个对象中第一个元素在原先集合中的索引位置
        $('#bar').index('li'); //1,传递一个选择器,返回#bar在所有li中的做引位置
        $('#bar').index(); //1,不传递参数,返回这个元素在同辈中的索引位置。  

4.each()方法

用来遍历选择器选择的结果集合
可以使用return false;提前退出循环

自己代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div, ul, li {
            margin: 0;
            padding: 0
        }

        li {
            float: left;
            width: 100px;
            height: 24px;
            line-height: 24px;
            list-style: none;
            border: solid 1px;
            text-align: center;
        }

        #cart {
            width: 700px;
            text-align: center;
        }

        .num input {
            width: 30px;
            text-align: center;
        }

        ul{
            background-color: cornflowerblue;

        }

        /*ul:nth-child(0) {*/
        /*background-color: aqua;*/
        /*}*/

        .num {
            width: 150px;
        }

        #total {
            clear: both;
            text-align: right;
            padding-right: 50px;
            padding-top: 5px;
        }

        #total span {
            color: red
        }
    </style>
    <script src="js/jquery-3.3.1.js"></script>
    <script>
        //除了这种先将所有事件绑定在一个模板Ul上,然后利用clone()的方法,还可以用
        //事件委托(利用事件冒泡原理实现)实现。
        var pro = ["电脑","u盘","充电器","鼠标"];
        var price = [10000,23,45,65];
        $(function(){
            //删除事件(除了删除行,如果改行选中则还需要将总价减去删除的)(可能引起全选框的变化)
            $("span:contains('删除')").click(function () {
                $(this).closest("ul").remove();
                if($(this).closest("ul").find("input[name=one]").prop("checked")){
                    var totalPrice = parseInt($("#total span").text()) - parseInt($(this).closest("ul").children().eq(4).text());
                    $("#total span").text(totalPrice+"");
                }
            });
            //给数量加按钮添加点击事件,同时改变商品总计(如果被选中要改变总价)
            $(".add").click(function(){
                //!!!注意选择这个ul的数量!!!
                var num =  parseInt($(this).closest("ul").find("input[name=num]").attr("value")) + 1;
                //注意此处要通过$(this)来选择这个ul的数量input!!!!!
                //错误!!!$("input[name=num]").attr("value",num+"");
                $(this).closest("ul").find("input[name=num]").attr("value",num+"");
                //此句是因为在改变文本框的值后在点击时文本框内容不改变,但是不用上一句的话元素的value值不变,
                $(this).closest("ul").find("input[name=num]").val(num);
                //改变总计
                var total = parseInt($(this).closest("ul").children().eq(4).text()) + parseInt($(this).closest("ul").children().eq(2).text())
                $(this).closest("ul").children().eq(4).text(total+"");
                //当商品被选中时,改变总价
                if($(this).closest("ul").find("input[name=one]").prop("checked")){
                    var totalPrice = parseInt($("#total span").text()) + parseInt($(this).closest("ul").children().eq(2).text());
                    $("#total span").text(totalPrice+"");
                }
            });
            //这里可以用trigger()函数模拟文本框的change()事件。
            /* $(".add").click(function(){
                 $(this).prev().val(parseInt($(this).prev().val)+1);
                 $(this).prev().triggle("change");
             });*/
            //给数量减按钮添加点击事件,同时改变总价,和商品总计
            $(".reduce").click(function(){
                if(parseInt($(this).closest("ul").find("input[name=num]").attr("value")) > 1){
                    var num1 =  parseInt($(this).closest("ul").find("input[name=num]").attr("value")) - 1;
                    $(this).closest("ul").find("input[name=num]").attr("value",num1+"");
                    $(this).closest("ul").find("input[name=num]").val(num1);
                    //改变总计
                    var total = parseInt($(this).closest("ul").children().eq(4).text()) - parseInt($(this).closest("ul").children().eq(2).text())
                    $(this).closest("ul").children().eq(4).text(total+"")
                    //如果当前商品被选中需要改变总价
                    if($(this).closest("ul").find("input[name=one]").prop("checked")){
                        var totalPrice = parseInt($("#total span").text()) - parseInt($(this).closest("ul").children().eq(2).text());
                        $("#total span").text(totalPrice+"");
                    }
                }
                //这里可以用trigger()函数模拟文本框的change()事件。
               /* $(".reduce").click(function(){
                    $(this).next().val(parseInt($(this).next().val)-1);
                    $(this).next().triggle("change");
                });*/
            });
            //给全选按钮添加事件(如果全选按钮选中,则将所有按钮不选中,否则将所有未选中的复选框选中)
            //改变总价
            $("input[name=all]").click(function () {
                //!!!!这里判读时对于元素而言已经完成了点击,因此在判断时实际上没选中的此时已经选中了
                if(!$(this).prop("checked")){
                    $("input:checkbox").each(function () {
                        //这里还需要改变总价,因为是全不选,直接设置为0
                        $(this).prop("checked",false);
                        $("#total span").text("0");
                    });
                }else{  //将没有选中的复选框选中,这里也需要改变总价,将未选中的商品价格加到总价中
                    $("input:checkbox").each(function () {
                        var totalPrice = parseInt($("#total span").text());
                        if(!$(this).prop("checked")){
                            totalPrice = totalPrice + parseInt($(this).closest("ul").children().eq(4).text());
                            $(this).prop("checked",true);
                        }
                        $("#total span").text(totalPrice+"");
                    });
                }
            });
            //给商品复选框添加事件(改变总价),当全部选中时,让全选框选中,同时改变总价
            $("input[name=one]").click(function () {
                var total;
                //这里反的是因为在判断时已经让其checked的值改变了???
                if($(this).prop("checked")){  //增加选中时(改变总价,如果全选按钮未选中并且所有按钮都已经选中了则让全选按钮选中)
                    total = parseInt($("#total span").text()) + parseInt($(this).parent("li").nextAll("li").eq(3).text());
                    var $allcheckbox = $(":checkbox");
                    var i = 1;
                    //判断是否所有按钮都选中,如果都选中了全选按钮也选中
                    for(i;i < $allcheckbox.length;i++){
                        if(!$allcheckbox.eq(i).prop("checked")){
                            break;
                        }
                    }
                    if(i == $allcheckbox.length){
                        $allcheckbox.eq(0).prop("checked",true);
                    }

                }else{          //取消选中时(改变总价,如果全选按钮是选中的总让其不选中)
                    total = parseInt($("#total span").text()) - parseInt($(this).parent("li").nextAll("li").eq(3).text());
                    if($(":checkbox:first").prop("checked")){
                        $(":checkbox:first").prop("checked",false);
                    }
                }
                $("#total span").text(total);
            });
            //文本框
            //这里文本框的修改事件可用change()事件
            //同时这里需要对文本框的值进行约束
            //给数量文本框添加focus事件和blur事件,该事件执行的是如果文本框内容发生改变,改变合计,并且如果商品是选中的则将总价改变
            var oldvalue = 1;
            //这里如果用attr("value")来操作,得不到改变后的值,不好操作使用val函数并没有改变vlaue值,因此在失去焦点应重新赋value值
            $("input[name=num]").focus(function () {
                oldvalue = $(this).val();
            });
            $("input[name=num]").blur(function () {
                var newvalue = parseInt($(this).val());
                //这里如果不重新设置value值,它是不会改变的
                $(this).attr("value",newvalue);
                if(oldvalue != newvalue){
                    //改变合计
                    var changed =  parseInt($(this).closest("ul").children().eq(2).text())*newvalue;
                    $(this).closest("ul").children().eq(4).text(changed+"");
                    //如果该商品被选中的话则让总价改变
                    if($(this).closest("ul").find("input[name=one]").prop("checked")){
                        var c =  parseInt($("#total span").text()) + parseInt($(this).closest("ul").children().eq(2).text())*(newvalue-oldvalue);
                        $("#total span").text(c+"");
                    }
                }
            });
            //使用change函数
            /*$("input[name=num]").change(function () {
                var textValue = $(this).val();
                if(textValue > 0){
                    $(this).parent().next().text(parseInt($(this).parent().prev().text())*textValue);
                } else if(textValue == 0){//删除商品
                    $(this).closest("ul").find("span:contains('删除')").trigger("click");
                }else{
                    $(this).val(1);
                    $(this).parent().next().text(parseInt($(this).parent().prev().text()));
                }
            });*/
        });
        $(function () {
            //注意要想用这种方法添加新商品,在删除前给元素加上事件
            var $model = $("#model").detach();
            //添加商品(改变总价)
            $("div+input").click(function () {
                //添加商品
                var index = parseInt(Math.random()*4);
                var newGoods = $model.clone(true);
                newGoods.children().eq(1).text(pro[index]);
                newGoods.children().eq(2).text(price[index]);
                newGoods.children().eq(4).text(price[index]);
                $("#total").before(newGoods);
                //判断全选按钮是否选中,如果选中将全选按钮去掉(关于prop()方法和attr()方法?)
                if($("input[name=all]").prop("checked")){
                    $("input[name=all]").prop("checked",false);
                }
            });
        });
    </script>
</head>
<body>
<div id="cart">
    <ul>
        <li><input name="all" type="checkbox">全选</li>
        <li>产品名称</li>
        <li>价格</li>
        <li class="num">数量</li>
        <li>合计</li>
        <li>操作</li>
    </ul>
    <ul id="model">
        <li><input name="one" type="checkbox"></li>
        <li>手机</li>
        <li>1000.00</li>
        <li class="num"><input type="button" value="-" class="reduce"> <input name="num" type="text" value="1"> <input type="button" value="+" class="add">
        </li>
        <li>1000.00</li>
        <li><span>删除</span></li>
    </ul>
    <div id="total">总价:<span>0.00</span></div>
</div>
<input name="add" type="button" value="添加">
</body>
</html>

老师代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div, ul, li {
            margin: 0;
            padding: 0
        }

        li {
            float: left;
            width: 100px;
            height: 24px;
            line-height: 24px;
            list-style: none;
            border: solid 1px;
            text-align: center;
        }

        #cart {
            width: 700px;
            text-align: center;
        }

        .num input {
            width: 30px;
            text-align: center;
        }

        ul {
            background-color: cornflowerblue;

        }

        /*ul:nth-child(0) {*/
        /*background-color: aqua;*/
        /*}*/

        .num {
            width: 150px;
        }

        #total {
            clear: both;
            text-align: right;
            padding-right: 50px;
            padding-top: 5px;
        }

        #total span {
            color: red
        }
    </style>
    <script src="js/jquery-3.3.1.js"></script>
    <script>
        var product = ["电脑", "u盘", "充电器", "鼠标"];
        var price = [10000, 23, 45, 65];
        $(function () {
//            $("input[name='add']").click(function () {
//                var i = Math.floor((Math.random()*4));//0-3
//                var node = $('<ul> <li><input name="one" type="checkbox"></li> <li>'+pro[i]+'</li> <li>'+price[i]+'</li> <li class="num"><input type="button" value="-"> <input name="num" type="text" value="1"> <input type="button" value="+"> </li> <li>'+price[i]+'</li> <li><span>删除</span></li> </ul>');
//                $("#total").before(node);
//            });
//            $("#cart").on("click","ul span",function () {
//                $(this).closest("ul").remove();
//            });
            //绑定所有事件
            //删除按钮删除
            $("#cart li span").click(function () {
                if (confirm("是否删除?")) {
                    $(this).closest("ul").remove();
                }
                //还需要判断是否被选中,如果选中需要改变总价
                calcTotal();
            });
            //文本框修改数据
            $("input[name='num']").change(function () {
                var $val = parseFloat($(this).val());
                if ($val > 0) {
                    $(this).parent().next().text($val * parseFloat($(this).parent().prev().text()));
                } else if ($val == 0) {
                    $("#cart li span").trigger("click");//模拟删除操作
                } else {
                    $(this).val(1);
                }
                calcTotal();
            });
            //减按钮操作
            $("input[value='-']").click(function () {
                $(this).next().val(parseInt($(this).next().val()) - 1);
                $("input[name='num']").trigger("change");
            });
            //加按钮操作
            $("input[value='+']").click(function () {
                $(this).prev().val(parseInt($(this).prev().val()) + 1);
                $("input[name='num']").trigger("change");
            });
            //选择框
            $("input[name='one']").click(function () {
                calcTotal();
                //还需判断当选中或者不选时,如果全都选中或者不选需要改变全选框的状态
            });
            //全选
            $("input[name='all']").click(function () {
                var $ret = $(this).prop("checked");
                //循环将所有复选框设置成同全选框一样的状态(注意这里是点击后的状态)
                $("input[name='one']").each(function () {
                    $(this).prop('checked', $ret);
                });
                //计算总价
                calcTotal();
            });
            var $modelNode = $("#cart ul:eq(1)").detach();
            $("input[name='add']").click(function () {
                var i = Math.floor((Math.random() * 4));//0-3
                var $cloneNode = $modelNode.clone(true);
                var $children = $cloneNode.children();
                $children.eq(1).text(product[i]);
                $children.eq(2).text(price[i]);
                $children.eq(4).text(price[i]);
                $("#total").before($modelNode);
            });
        })
        //计算总价
        function calcTotal() {
            var total = 0;
            var $checkBox = $("input[name='one']");
            var $price = $(".price");
            $checkBox.each(function () {
                if ($(this).prop("checked")) {
                    var i = $checkBox.index($(this));
                    total += parseFloat($price.eq(i).text());
                }
            });
            $("#total span").text(total);
        }
    </script>
</head>
<body>
<div id="cart">
    <ul>
        <li><input name="all" type="checkbox">全选</li>
        <li>产品名称</li>
        <li>价格</li>
        <li class="num">数量</li>
        <li>合计</li>
        <li>操作</li>
    </ul>
    <ul>
        <li><input name="one" type="checkbox"></li>
        <li>手机</li>
        <li>1000.00</li>
        <li class="num"><input type="button" value="-"> <input name="num" type="text" value="1"> <input type="button"
                                                                                                        value="+"></li>
        <li class="price">1000.00</li>
        <li><span>删除</span></li>
    </ul>
    <div id="total">总价:<span>0.00</span></div>
</div>
<input name="add" type="button" value="添加">
</body>
</html>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值