这个案例拖延了三天,今天终于给补上了。
购物车结算的功能,主要就是更新商品的数据了。主要利用的知识是jQuery中元素的获取、获取元素的子元素或父元素、操作元素属性和元素的文本内容以及对jQuery选择器的应用,等等吧。反正就是把JavaScript里的操作在这里更好的用jQuery实现。
这个案例的核心价值我认为就是数据的获取与转换,以及遍历元素。练习的价值还是挺高的,还有就是更让我们清除的认识到结构的作用。
废话不多说,先看下我们需要实现的几个功能吧。
如图所示,五个部分。
1. 全选按钮 和 商品对应的按钮。
这个部分有两个部分,首先是全选按钮选中时下面所有的商品按钮会选中;其次就是商品部分的按钮全选中时全选按钮被选中,有一个商品按钮没有选中时全选按钮就不选中。
这里注册事件是用change事件,表示表单发生变化,简单来说就是表单checked属性发生变化。代码里面的注释很详细了,可以看看哈。
// 1.实现全选按钮控制小按钮
// 1.1 小按钮的状态与全选按钮的状态保持一致 prop()固有属性检测表单是否被选中
$(".checkall").change(function () {
$(".j-checkbox, .checkall").prop("checked", $(this).prop("checked"));
// 改变背景色
if ($(this).prop("checked")) {
// 添加类 改变背景色
$(this).parents(".cart-item").addClass("check-cart-item");
} else {
// 移除类
$(this).parents(".cart-item").toggleClass("check-cart-item");
}
getSum();
})
// 1.2 小按钮的状态决定全选按钮状态
$(".j-checkbox").change(function () {
// if(按钮选中的个数 === 按钮的总个数){
// 全选选中
// }else{
// 不选择全选
// }
if ($(".j-checkbox:checked").length === $(".j-checkbox").length) {
$(".checkall").prop("checked", true);
} else {
$(".checkall").prop("checked", false);
}
// 选中时,背景色改变
// ele.parents("指定父级元素")
if ($(this).prop("checked")) {
$(this).parents(".cart-item").addClass("check-cart-item");
} else {
$(this).parents(".cart-item").toggleClass("check-cart-item");
}
// 重新计算小计部分
getSum();
})
2. 点击+ - 按钮,实现商品数量的变化;3. 按钮-/+改变商品数量,同时更新商品总价
这里就是注册点击事件,核心就是确定的是当前点击的按钮对应的表单的值变化。通过当前点击的元素找到对应的表单,获取表单的值是使用val()方法,普通元素的内容是text()和html()。+按钮的实现过程与-相似,+有详细的过程。-按钮需要做一个判断,商品数不能小于0.
这里我们这更新总价放一块了,以为点击-/+按钮时,右边的小计部分就要实时变化。
// 2.点击+ -按钮来增加和减少商品数量
// 2.1 +添加数量
$(".increment").click(function () {
// 获取当前 + 的兄弟表单的值
var n = $(this).siblings(".itxt").val();
// 然后点击一次自增——商品数量
n++;
// console.log(n);
// 数量:表单的商品数量
$(this).siblings(".itxt").val(n);
// 当前被点击的 + 区域对应的单价
var p = $(this).parents(".p-num").siblings(".p-price").text();
// 返回的是字符串 所以要把¥截取掉 使用substr()截取
// 截取后还是字符串,用parseFloat转换为数值型
p = parseFloat(p.substr(1));
console.log(p);
// 获取当前的总价
var price = $(this).parents(".p-num").siblings(".p-sum").text();
// 去掉¥符号
price = parseFloat(price.substr(1));
// 保留两位小数点 toFixed(2)
price = (p * n).toFixed(2);
console.log(price);
// 把计算好的商品总和价放到标签里
$(this).parents(".p-num").siblings(".p-sum").text("¥" + price);
// 重新计算小结部分的总额
getSum();
})
// 2.2 -号减少数量
$(".decrement").click(function () {
// 一定是当前加号的兄弟表单的值自增
var n = $(this).siblings(".itxt").val();
// 商品数量
n--;
console.log(n);
// 三元表达式:判断数量不能小于0
n = n <= 0 ? 1 : n;
$(this).siblings(".itxt").val(n);
// 当前+号区域的单价
var p = $(this).parents(".p-num").siblings(".p-price").text();
p = parseFloat(p.substr(1));
console.log(p);
// 获取当前的总价
var price = $(this).parents(".p-num").siblings(".p-sum").text();
// 去掉¥符号
price = parseFloat(price.substr(1));
price = (p * n).toFixed(2);
console.log(price);
$(this).parents(".p-num").siblings(".p-sum").text("¥" + price);
getSum();
})
做到这里,能实现点击-/+按钮,改变商品数量,对应的小计也发生变化。但是,这里存在一个bug,就是当用户自己输入商品数量时,小计部分的总额是不变化的,这就很惊悚了。
所以,这里还需要判断一下用户改变表单内容的事件。可以用change事件注册,但是用户体验不好,需要在空白处点击一次小计才会更新,这里我用的是键盘弹起keyup事件。
// 3. 这样的话 有一个bug,当用户自己更改表单的内容时就会出错
$(".itxt").keyup(function () {
var n = $(this).val();
var p = $(this).parents(".p-num").siblings(".p-price").text();
p = parseFloat(p.substr(1));
var price = $(this).parents(".p-num").siblings(".p-sum").text();
// 去掉¥符号
price = parseFloat(price.substr(1));
price = (p * n).toFixed(2);
console.log(price);
$(this).parents(".p-num").siblings(".p-sum").text("¥" + price);
getSum();
})
4. 结算购物车部分
这部分用到了jQuery元素的遍历,each()。jQuery中存在的隐式迭代是对不同元素进行相同的操作,现在我们需要对不同的元素做不同的操作,此时我们就需要遍历元素了。遍历每个模块中的商品数量进行累加就是购物车总数量,遍历每个模块中的商品小计进行累加就是购物车结算总额。我们可以封装一个函数,因为只有有变动我们都需要更新数据,实时更新购物车对应的数据,所以封装一个函数比较好。这就不难解释,为什么每次点击-/+按钮时,需要在最后调用一次本函数了。
注意:只有商品被选中时,才会参与购物车结算的。
// 封装一个函数,用来计算小结的内容
function getSum() {
var totalNumber = 0; // 总件数
var totalPrice = 0; // 总价钱
// 遍历car-item所有的表单中的商品数量 累加 算出所有商品的总数量
$(".itxt").each(function (i, ele) {
// 判断 商品对应的按钮是否选中,选中才会结算 不选中不参与结算
var singleBtn = $(this).parents(".p-num").siblings(".p-checkbox").children(".j-checkbox");
if (singleBtn.prop("checked")) {
totalNumber += parseFloat($(ele).val());
}
})
$(".amount-sum em").text(totalNumber);
// 遍历每个car-item中的商品总计 累加起来算出所有商品价
$(".p-sum").each(function (i, ele) {
var singleBtn = $(this).siblings(".p-checkbox").children(".j-checkbox");
if (singleBtn.prop("checked")) {
totalPrice += parseFloat($(ele).text().substr(1));
}
})
$(".price-sum em").text("¥" + totalPrice.toFixed(2));
}
5.删除模块
这部分比较简单,就是点击事件的注册,主要是要找到点击时,删除对应的父结构。切记切记,删除的永远是当前被点击按钮对应的结构,核心就是this的问题。
// 5. 删除模块
// 删除按钮
$(".p-action a").click(function () {
$(this).parents(".cart-item").remove();
getSum();
})
// 删除选中的商品
$(".operation .remove-batch").click(function () {
$(".j-checkbox:checked").parents(".cart-item").remove();
getSum();
})
// 清空购物车
$(".operation .clear-all").click(function () {
$(".cart-item").remove();
getSum();
})
删除第一个后:
点击删除所选中商品按钮:
清空:
最后附上结构代码,一个商品列部分。
<div class="cart-item">
<div class="p-checkbox">
<input type="checkbox" name="" id="" class="j-checkbox">
</div>
<div class="p-goods">
<div class="p-img">
<img src="upload/p2.jpg" alt="">
</div>
<div class="p-msg">【2000张贴纸】贴纸书 3-6岁 贴画儿童 贴画书全套12册 贴画 贴纸儿童 汽</div>
</div>
<div class="p-price">¥24.80</div>
<div class="p-num">
<div class="quantity-form">
<a href="javascript:;" class="decrement">-</a>
<input type="text" class="itxt" value="1">
<a href="javascript:;" class="increment">+</a>
</div>
</div>
<div class="p-sum">¥24.80</div>
<div class="p-action"><a href="javascript:;">删除</a></div>
</div>
完整的html
<div class="c-container">
<div class="w">
<div class="cart-filter-bar">
<em>全部商品</em>
</div>
<!-- 购物车主要核心区域 -->
<div class="cart-warp">
<!-- 头部全选模块 -->
<div class="cart-thead">
<div class="t-checkbox">
<input type="checkbox" name="" id="" class="checkall"> 全选
</div>
<div class="t-goods">商品</div>
<div class="t-price">单价</div>
<div class="t-num">数量</div>
<div class="t-sum">小计</div>
<div class="t-action">操作</div>
</div>
<!-- 商品详细模块 -->
<div class="cart-item-list">
<div class="cart-item check-cart-item">
<div class="p-checkbox">
<input type="checkbox" name="" id="" checked class="j-checkbox">
</div>
<div class="p-goods">
<div class="p-img">
<img src="upload/p1.jpg" alt="">
</div>
<div class="p-msg">【5本26.8元】经典儿童文学彩图青少版八十天环游地球中学生语文教学大纲</div>
</div>
<div class="p-price">¥12.60</div>
<div class="p-num">
<div class="quantity-form">
<a href="javascript:;" class="decrement">-</a>
<input type="text" class="itxt" value="1">
<a href="javascript:;" class="increment">+</a>
</div>
</div>
<div class="p-sum">¥12.60</div>
<div class="p-action"><a href="javascript:;">删除</a></div>
</div>
<div class="cart-item">
<div class="p-checkbox">
<input type="checkbox" name="" id="" class="j-checkbox">
</div>
<div class="p-goods">
<div class="p-img">
<img src="upload/p2.jpg" alt="">
</div>
<div class="p-msg">【2000张贴纸】贴纸书 3-6岁 贴画儿童 贴画书全套12册 贴画 贴纸儿童 汽</div>
</div>
<div class="p-price">¥24.80</div>
<div class="p-num">
<div class="quantity-form">
<a href="javascript:;" class="decrement">-</a>
<input type="text" class="itxt" value="1">
<a href="javascript:;" class="increment">+</a>
</div>
</div>
<div class="p-sum">¥24.80</div>
<div class="p-action"><a href="javascript:;">删除</a></div>
</div>
</div>
<!-- 结算模块 -->
<div class="cart-floatbar">
<div class="select-all">
<input type="checkbox" name="" id="" class="checkall">全选
</div>
<div class="operation">
<a href="javascript:;" class="remove-batch"> 删除选中的商品</a>
<a href="javascript:;" class="clear-all">清理购物车</a>
</div>
<div class="toolbar-right">
<div class="amount-sum">已经选<em>1</em>件商品</div>
<div class="price-sum">总价: <em>¥12.60</em></div>
<div class="btn-area">去结算</div>
</div>
</div>
</div>
</div>
</div>