随着vue、react、angular等MVVM框架的兴起。让之前需要对dom进行复杂操作才能实现的需求变得如此简单。确实,作为数据驱动dom的框架,让我们在项目中变得愈加游刃有余。但是当我们享受他给我们带来的便利时,适当的对原生的了解也能对我们技术的提升大有裨益。而且通过适当的编写js原生代码实现相应功能,也能更让我们喜欢上MVVM框架。废话少说:先通过效果图(左边为编辑购物车,右边为购物车列表)了解下需求:
- 当点击商品复选框,当前商品的总价会被计算到合计费用中去
- 当点击商品数量增减且此时商品对应的复选框处于选中状态时,合计费用会发生改变
- 点击全选时,所有商品的复选框都被选中且合计费用为所有商品总价
- 点击编辑,此处文字变为“完成”,右下角的去结算按钮变为红色删除按钮
- 在编辑购物车情况下,当我们勾选对应商品的复选框然后点击删除,对应的商品会被清除,且合计费用为重置为0,“完成”变为“编辑”,删除按钮变为去结算。
需求痛点:这个需求的难点在于如何去将每个商品的总价汇集起来然后随着复选框的状态累加到合计费用中去。我们先看下商品的html结构:
<div class="cartMain1" data-id=${goods_id}>
<input type="checkbox" class="checkbox" />
<input type="hidden" class="hiddenVal">
<div class="cartMsg">
<img src="${goods_image}" alt="" />
<div class="cartDetail2">
<h3>${goods_name}</h3>
<div class="cartDCont">
<p class="commonMoney">¥<span class="singlePrice">${goods_price_max}</span></p>
<div class="count">
<button class="decrease">-</button>
<input type="text" class="goodsSum" value=${goods_num} />
<button class="increase">+</button>
</div>
</div>
</div>
</div>
</div>
我是这样解决上述难点的:我在每个商品的复选框下面增加一个隐藏域,它的值为当前商品的总价,当商品的数量发生改变时,我会将商品最终价格赋值各他的value值,然后我们在通过遍历所有复选框的选中状态拿到对应的隐藏域value值就得出我们想要的总价了。具体js代码如下:
1、遍历隐藏input的值获取金额
function getHiddenMoney() {
let str = 0;
Array.from(checkboxEl).forEach((item) => {
if (item.checked == true) {
str += +item.nextElementSibling.value;
}
});
document.querySelector(".totalPrice").innerHTML = str.toFixed(2);
}
2、点击子复选框将金额赋值给隐藏input
function toHiddenMoney(el) {
const parent = el.parentNode;
//获取单价元素
const singlePrice = +parent.querySelector(".singlePrice").innerHTML;
//获取商品数量
const goodsSum = +parent.querySelector(".goodsSum").value;
//商品总价为
let totalPriceVal = (singlePrice * goodsSum).toFixed(2);
//赋值给hidden input框
el.nextElementSibling.value = totalPriceVal;
getTotalMoney();
}
3、点击子复选框给父复选框添加状态
for (let i = 0; i < box.length; i++) {
box[i].addEventListener("click", function () {
checkbox.checked = Array.from(box).every((item) => item.checked);
toHiddenMoney(box[i]);
});
}
4、点击全选复选框=>所有复选框都被选中
const checkbox = document.querySelector("#checkbox");
const box = document.querySelectorAll(".checkbox");
checkbox.addEventListener("click", function () {
for (let i = 0; i < box.length; i++) {
box[i].checked = checkbox.checked;
toHiddenMoney(box[i]);
}
});
5、点击商品数量增减时
let goodCount = document.querySelectorAll(".count");
goodCount.forEach((item) => {
item.addEventListener("click", function (e) {
let target = e.target;
if (target.className == "decrease") {
const inp = target.nextElementSibling;
const hidden =
target.parentNode.parentNode.parentNode.parentNode
.previousElementSibling;
const checkBox =
target.parentNode.parentNode.parentNode.parentNode
.previousElementSibling.previousElementSibling;
const singleVal =
+target.parentNode.previousElementSibling.querySelector(
".singlePrice"
).innerHTML;
if (inp.value == 1) {
return alert("不能再减了~");
} else {
inp.value--;
hidden.value = singleVal * inp.value;
toHiddenMoney(checkBox);
}
}
if (target.className == "increase") {
const inp = target.previousElementSibling;
const hidden =
target.parentNode.parentNode.parentNode.parentNode
.previousElementSibling;
const checkBox =
target.parentNode.parentNode.parentNode.parentNode
.previousElementSibling.previousElementSibling;
const singleVal =
+target.parentNode.previousElementSibling.querySelector(
".singlePrice"
).innerHTML;
inp.value++;
hidden.value = singleVal * inp.value;
toHiddenMoney(checkBox);
}
});
});
const checkboxEl = document.querySelectorAll(".checkbox");
6、点击编辑
const edit = document.querySelector(".edit");
let flag = true;
const editHtml = edit.innerHTML;
const account = document.querySelector(".account");
const cancel = document.querySelector(".cancel");
let newCheckbox = [];
edit.addEventListener("click", function () {
let editHtml2 = `<span style="color: red; font-size: 3.7333vw">完成</span>`;
console.log(flag);
if (flag) {
this.innerHTML = editHtml2;
account.style.display = "none";
cancel.style.display = "block";
} else {
this.innerHTML = editHtml;
account.style.display = "block";
cancel.style.display = "none";
}
flag = !flag;
});
7、点击删除按钮
let goodsIdArr = [];
cancel.addEventListener("click", function () {
//获取被选中的复选框
newCheckbox = [...checkboxEl].filter((item) => item.checked == true);
newCheckbox.forEach((item) => {
item.parentNode.remove();
goodsIdArr.push(item.parentNode.dataset.id);
});
edit.innerHTML = editHtml;
account.style.display = "block";
cancel.style.display = "none";
document.querySelector(".totalPrice").innerHTML = +0.0;
});
8、封装获取复选框的状态来计算总费用
function getTotalMoney() {
let checkboxNew = document.querySelectorAll(".checkbox");
arr = [];
for (let i = 0; i < checkboxNew.length; i++) {
if (checkboxNew[i].checked == true) {
arr.push(+checkboxNew[i].nextElementSibling.value);
getTotalPrice(arr);
} else {
getTotalPrice(arr);
}
}
}
9、计算总价
function getTotalPrice(arr) {
document.querySelector(".totalPrice").innerHTML = arr
.reduce((prev, cur) => prev + cur, 0)
.toFixed(2);
}
以上就是我用原生js实现购物车总金额的代码。写的时候也是备受煎熬。用原生js真的很繁琐。我的代码逻辑我觉得还有改进的地方,还望各位大神指点指点。欢迎大家点评~