购物车练习总结
初学练习,收货颇多。两个方便,一部分是技术知识上的,一部分是开发思路上的。
整个练习的业务逻辑包括:
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>
这篇博客总结了作者在实现jQuery购物车功能时的学习经历,包括动态添加商品、全选、复选框、数量增减、文本框变化、删除操作的业务逻辑。通过实践,作者认识到事件处理、代码复用和事件代理的重要性,并分享了关于val()、attr()、prop()、index()和each()方法的理解。

1081

被折叠的 条评论
为什么被折叠?



