代码:
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style>
*{ margin:0; padding:0; font-size:14px}
#box{ width:600px; margin:100px auto; table-layout: fixed;}
table,th,td{ border:1px solid #000; border-collapse:collapse}
td,th{ width:100px; height:46px; padding:10px}
input[type="text"]{ display:none; height:24px; width:60px; border:1px solid #ccc;}
tbody tr td{text-align: center;}
tfoot td{text-align: right;}
.editBtn{ color:#666}
.delBtn{ color:red}
.sureBtn,.cancelBtn{ display:none}
.edit span{ display:none}
.edit input[type="text"]{ display:inline-block}
.edit .editBtn,.edit .delBtn{ display:none}
.edit .sureBtn,.edit .cancelBtn{ display:inline}
</style>
</head>
<body>
<div>
<table id="box">
<thead>
<tr>
<th>
<label>全选:<input type="checkbox" id="allCheck" class="allCheck"/></label><br>
</th>
<th>名称</th>
<th>单价</th>
<th>数量</th>
<th>小计</th>
<th>处理</th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<td colspan="6">总价:¥<b id="moneyContainer"></b></td>
</tr>
</tfoot>
</table>
</div>
<script>
class Cart {
constructor(selector) {
this.container = document.querySelector(selector);
this.tbody = this.container.querySelector("tbody");
this.allCheck = this.container.querySelector("#allCheck"); // 全选按钮
this.reCheck = this.container.querySelector("#reCheck"); // 反选按钮
this.moneyContainer = this.container.querySelector("#moneyContainer"); // 放总价的容器
this.check = null; // 先声明所有的单选按钮集合,render()中渲染后查找
this.n = 0; //记录单选个数
this.allMoney = 0; // 记录总价
this.json = [
{"name" : "辣条", "price" : 10, "num" : 1},
{"name" : "棒棒糖", "price" : 20, "num" : 1},
{"name" : "跳跳糖", "price" : 15, "num" : 1},
{"name" : "泡泡糖", "price" : 2, "num" : 1}
];
this.render(); // 渲染
this.calcMoney(); // 计算总价
}
// 将JSON通过字符串模板渲染表格
render () {
let formwork = "";
this.json.forEach(item => {
formwork += `
<tr>
<td><input type="checkbox" class="check"/></td>
<td>${item.name}</td>
<td>${item.price}</td>
<td><span>${item.num}</span><input type="text"></td>
<td>${item.price * item.num}</td>
<td>
<a href="javascript:;" class="editBtn">编辑</a>
<a href="javascript:;" class="sureBtn">确定</a>
<a href="javascript:;" class="cancelBtn">取消</a>
<a href="javascript:;" class="delBtn">删除</a>
</td>
</tr>`;
});
this.tbody.innerHTML = formwork;
this.check = Array.from(this.tbody.querySelectorAll(".check"));
this.bindEvents(); // 执行绑事件
}
// 绑事件
bindEvents () {
this.tbody.onclick = e => {
e = e||window.event;
let target = e.target||e.srcElement;
let tr = target.parentNode.parentNode; // 找到点击事件所在的tr,作为实参传递
switch(target.className) {
case "editBtn" : this.editBtnClick(tr); break;
case "sureBtn" : this.sureBtnClick(tr); break;
case "cancelBtn" : this.cancelBtnClick(tr); break;
case "delBtn" : this.delBtnClick(tr); break;
} // 事件委托,this指向事件对象table
}
this.check.forEach(check => {
check.onchange = this.checkChange.bind(this,check); // bind()改变指向,并且将事件对象作为实参传递
// check.onchange = () => {this.checkChange(check);} // 箭头函数也可以完成
})// 给所有的单选按钮绑事件。不改变指向,this会指向事件对象,需要改变指向table(认清与上面事件委托的区别)
this.allCheck.onchange = this.allCheckChange.bind(this); //给全选按钮绑事件
}
checkChange (check) {
// console.log(this);
this.n += check.checked ? 1 : -1;
allCheck.checked = this.n == this.check.length;
this.calcMoney(); // 每次选择后计算总价
}
//难点。对上面代码的总结:
//必须传参
//不能在点击事件找到对象环境
//不能在对象环境找到点击事件
allCheckChange(){
// console.log(this);
this.check.forEach(item=>{
item.checked = this.allCheck.checked;
})
this.n=this.allCheck.checked?this.check.length:0;
this.calcMoney(); // 每次选择后计算总价
}
editBtnClick (tr) {
tr.classList.add("edit"); // 添加class名,进入编辑模式
let span = tr.querySelector("span");
span.nextElementSibling.value = span.innerHTML; // 提取
}
sureBtnClick (tr) {
let span = tr.querySelector("span");
span.innerHTML = span.nextElementSibling.value; // 替换
let td = Array.from(tr.querySelectorAll("td"));
td[4].innerHTML = span.innerHTML * td[2].innerHTML;// 每次修改后修改小结
tr.classList.remove("edit"); // 替换后移除class名,退出编辑模式
this.calcMoney();// 每次修改后计算总价
}
cancelBtnClick (tr) {tr.classList.remove("edit");}
delBtnClick (tr) {
let shopName = tr.querySelectorAll("td")[1].innerHTML;
if(confirm(`确认不要${shopName}了吗?`)){
tr.remove();
this.n=0;
this.check = Array.from(this.tbody.querySelectorAll(".check"));
this.check.forEach(check=>{if(check.checked) this.n++;}) // 每次删除后计算n
}
this.allCheck.checked = this.n===this.check.length;
this.calcMoney(); // 每次删除后计算总价
}
calcMoney () {
// console.log(this);
console.log(this.n);
this.allMoney = 0; // 每次重置为0,从头算
Array.from(this.tbody.children).forEach(tr => { // 找到所有的tr
if(tr.querySelector(".check").checked){
this.allMoney += Number(tr.querySelectorAll("td")[4].innerHTML);
} // 判断当前商品是否选中,选中的累加
})
this.moneyContainer.innerHTML = this.allMoney;
}
}
new Cart("#box");
</script>
</body>
</html>
效果图: