购物车的选择和购物车商品数量的调整
一、购物车的选择
要实现购物车中商品的选择,包括商品的单选和所有商品的全选。
第一步实现商品全选的函数:
1.创建checkAll 函数——实现商品的全选
这个函数的作用是选中或取消选中购物车中的所有商品。
当用户点击页面顶部的全选复选框时,会触发这个函数。
函数接收一个参数 checked,这个参数表示全选复选框的选中状态(true 表示选中,false 表示未选中)。
函数内部通过 document.querySelectorAll(“.my-box”) 获取页面上所有的商品复选框,并将它们的选中状态设置为与全选复选框一致。
const checkAll = (checked) => {
const boxes = document.querySelectorAll(".my-box");
for (let i = 0; i < boxes.length; i++) {
boxes[i].checked = checked;
}
}
函数解释:
- 参数checked是代表商品选择状态的布尔值变量,ture表示商品全选,false表示不全选。
- 其后我们通过类选择器找到所有匹配的元素,也就是选择所有带有 my-box 类的复选框元素。,并将document.querySelectorAll的NodeList类型的返回值放在boxes对象中。
在每一个商品卡片都有一个复选框:
<td class="ps-4" >
<input style="transform: scale(1.5);" class="form-check-input my-box"
onclick="checkSingle()"
type="checkbox" value="${item.meal_id}">
</td>
在这里from-check-input
是 Bootstrap 框架中的一个类名,它用于样式化 HTML 表单中的复选框(checkbox)和单选按钮(radio button)元素,其后的my-box
就是它的类名。代码中 type="checkbox"
定义了这是一个复选框。所以checkAll函数回匹配所有my-box的元素,通过遍历统一设置复选框状态,达到全选或全不选的效果。
- 目前我们只涉及到了两种选择器:
类选择器(Class Selector)
:以点(.)开头,后面跟着类名。它用于选择所有具有指定类的元素。
ID 选择器(ID Selector)
:以井号(#)开头,后面跟着 ID 名称。它用于选择具有指定 ID 的单个元素。 - 函数的最后然后遍历对象,把所有匹配的元素的选择状态都设置为入参的状态。
2.创建checkSingle 函数——实现商品的单选
这个函数的作用是更新全选复选框的状态,以反映用户对单个商品复选框的操作。
代码逻辑:当用户选中或取消选中任何一个商品复选框时,会触发这个函数。
函数内部首先获取所有商品复选框,然后检查它们是否全部被选中。
如果所有商品复选框都被选中,则全选复选框也被设置为选中状态;如果有任何一个商品复选框未被选中,则全选复选框也被设置为未选中状态。
const checkSingle = () => {
document.querySelector(".all-box").checked = document.querySelectorAll(".my-box:checked").length === document.querySelectorAll(".my-box").length;
}
函数里面就只有一行代码。但是我们将代码分开会比较好理解一点。
document.querySelector(".all-box").checked:
这行代码使用 document.querySelector 方法选择页面上具有 .all-box 类的复选框元素。
.checked 属性用于获取或设置该复选框的选中状态。document.querySelectorAll(".my-box:checked").length:
这行代码使用 document.querySelectorAll 方法选择页面上所有已经被选中的具有 .my-box 类的复选框元素。
:checked 是一个伪类选择器,用于选择所有选中状态的复选框。
.length 属性返回选中的复选框数量。document.querySelectorAll(".my-box").length:
这行代码使用 document.querySelectorAll 方法选择页面上所有具有 .my-box 类的复选框元素。
.length 属性返回所有这些复选框的数量。document.querySelector(".all-box").checked = document.querySelectorAll(".my-box:checked").length === document.querySelectorAll(".my-box").length;
这是一个赋值操作,它将 .all-box 类复选框的选中状态设置为两个长度相等的条件。
如果所有具有 .my-box 类的复选框都被选中(即选中的数量等于总数),那么 .all-box 类复选框也将被设置为选中状态(true)。
如果不是所有具有 .my-box 类的复选框都被选中,那么 .all-box 类复选框将被设置为未选中状态(false)。
函数完成后,我们要在HTML相应的板块添加点击事件来调用函数:
全选复选框处,添加点击事件调用checkAll函数:
<th class="ps-4">
<input style="transform: scale(1.5);" class="form-check-input all-box" onclick="checkAll(this.checked)"
type="checkbox" value="">
</th>
商品卡片复选框添加点击事件调用checkSingle函数
<td class="ps-4" >
<input style="transform: scale(1.5);" class="form-check-input my-box"
onclick="checkSingle()"
type="checkbox" value="${item.meal_id}">
</td>
注意:HTML 复选框(checkbox)元素本身不自带点击属性,但是它们具有一些内置的行为和事件,所以在上一篇文章,获取购物车清单时用户可以点击复选框来切换它的选中状态。
在这里我们添加onclick属性点击事件来获取选中状态或调用函数。
到这里购物车的选择就做好了,只涉及前端。
二、购物车商品数量的调整
效果实现要求,用户通过商品数量旁的加减号实现商品数量的增加或减少。同时后端数据库中的数据也要及时的做出变化,保证数据一致。
1.前端
要实现通过点击加减号来进行增减商品,我们为商品的加减号处的元素进行修改,添加onclick点击相应事件,调用函数:
<div class="input-group" style="width:150px;">
<span onclick="changeNum('${item.s_id}','${item.meal_id}','-')"class="fs-4 text-white bg-danger text-center " style="width:40px;cursor:pointer;" >-</span>
<input readonly id="cartitem_num_${item.s_id}" type="text" class="form-control form-control-sm text-center fs-5 text-danger" value="${item.s_num}" />
<span onclick="changeNum('${item.s_id}','${item.meal_id}','+')"class="fs-4 text-white bg-danger text-center " style="width:40px;cursor:pointer;" >+</span>
</div>
完成后就需要实现函数像后端传达:
const changeNum = async (s_id, meal_id, opr) => {
let s_num = parseInt(document.querySelector(`#cartitem_num_${s_id}`).value);
s_num = opr == '+' ? (s_num + 1) : (s_num - 1);
const resp = await fetch(`cart/num?meal_id=${meal_id}&s_num=${s_num}`);
if (!resp.ok) {
toast("失败", "更改数量失败!");
return;
}
const result = await resp.json();
if (!result.success) {
toast("失败", result.message);
return;
}
if (s_num < 1) {
const dom = document.querySelector(`#cartitem_tr_${s_id}`);
dom.remove();
} else {
document.querySelector(`#cartitem_num_${s_id}`).value = s_num;
}
}
代码解释
1. const changeNum = async (s_id, meal_id, opr) => { ... }:
这里定义了一个名为 changeNum 的异步函数,它接受三个参数:s_id:商品的唯一标识符(通常是数据库中的ID),meal_id:与 s_id 相关联的餐品ID,opr:操作符,用于指示数量是增加(‘+’)还是减少(‘-’)。
2. let s_num = parseInt(document.querySelector(#cartitem_num_${s_id}).value);
:代码通过 querySelector 方法和 s_id 来获取对应商品数量输入框的值,parseInt 函数将输入框的值转换为整数。
3. s_num = opr == '+' ? (s_num + 1) : (s_num - 1);
:这行代码使用三元运算符来决定是增加还是减少商品数量,如果 opr 是 ‘+’,则数量增加1,如果 opr 是 ‘-’,则数量减少1。
4. const resp = await fetch(cart/num?meal_id=${meal_id}&s_num=${s_num});
:用 fetch 函数向服务器发送一个请求,以更新商品的数量,请求的 URL 包含 meal_id 和新的 s_num 值。
5. 下一步检查响应对象的 ok 属性,如果请求失败,则显示一个错误消息。
6. 如果相应欧克那么,再代码解析响应体中的 JSON 数据。
7. 继续检查从服务器返回的结果是否包含 success 属性,如果不成功,则显示错误消息。
8. 对数量经行判断,检查更新后的数量是否小于1。如果是,那么从DOM中移除该商品的行,表示该商品已从购物车中删除。如果不是,那么更新输入框的值为新的数量。
前端就完成了,就要开始后端,处理前端发过来的响应了
2.后端
前端有数据信息包含在响应中,所以我们要建立一个类存放数据
2.1创建ShoppingCartDto类
public class ShoppingCartDto {
private Long meal_id;
private Integer s_num;
public Long getMeal_id() {
return meal_id;
}
public void setMeal_id(Long meal_id) {
this.meal_id = meal_id;
}
public Integer getS_num() {
return s_num;
}
public void setS_num(Integer s_num) {
this.s_num = s_num;
}
}
这是一个实体类包含meal_id和s_num属性,以及相应的get、set方法,也就是对应的从前端传过来的数据。
2.2在CartServlet类中添加修改购物车餐品数量功能
此前我们在这个类中实现了购物车清单的功能,现在我们要在这个类中再添加一个修改购物车商品数量的功能。
首先是熟悉的配方熟悉的配料:
第一步,增加注解中的路径,以调用不同的方法:
@WebServlet({
"/cart/list",
"/cart/num"
})
第二步,在switch分支结构中新增case板块:
case "/cart/num":
cartNum(req,resp);
break;
第三步,实现函数:
private void cartNum(HttpServletRequest req, HttpServletResponse resp) throws IOException {
User user =(User) req.getSession().getAttribute("CurrUser");
if(user==null){
MyWeb.printJson(resp,R.err("请先登录"));
return;
}
ShoppingCartDto cartDto =MyWeb.getBeanFromRequest(ShoppingCartDto.class,req);
String sql ="delete from t_shoppingcart where u_id= ? and meal_id = ?";
if(cartDto.getS_num()<1){
DaoCreater.currentDao().update(sql,user.getU_id(),user,cartDto.getMeal_id());
}else {
sql = "update t_shoppingcart set s_num = ? where u_id = ? and meal_id = ?";
int count = DaoCreater.currentDao().update(sql, cartDto.getS_num(), user.getU_id(), cartDto.getMeal_id());
}
MyWeb.printJson(resp,R.OK());
}
- 依旧是先从Session中获取我们的用户信息,若没有,那就让返回响应告诉前端提示用户先登录用户先登录。
- 如果有登录的用户那就获取响应中的数据,存在ShoppingCartDto对象中。
- 编写sql语句,当数量不足一个,也就是用户将当前商品数量调整为零,那么就去除购物车中的商品,数据去执行删除操作。
- 其余情况就更新数据库数据为用户调整的数据,使用if…else…语句判断执行sql语句。
- 最后返回成功状态的响应