<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
table {
border-collapse: collapse;
}
td {
border: 1px solid gray;
padding: 10px;
text-align: center;
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<td><input type="checkbox" />全选</td>
<td>序号</td>
<td>商品名</td>
<td>单价</td>
<td>数量</td>
<td>小计</td>
</tr>
</thead>
<tbody>
<tr>
<td>xxx</td>
<td>xxx</td>
<td>xxx</td>
<td>
<button>-</button>
<span>xxx</span>
<button>+</button>
</td>
<td>xxx</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="6">合计:xxx</td>
</tr>
</tfoot>
</table>
<script>
const products = [
{ name: '苹果', price: 10, count: 30, checked: true },
{ name: '香蕉', price: 6, count: 3, checked: true },
{ name: '柿子', price: 26, count: 1, checked: true },
{ name: '哈密瓜', price: 19, count: 45, checked: true },
]
const products_el = products.map((value, index) => {
const { count, name, price, checked } = value
// 添加自定义属性: index, 保存序号
return `<tr data-index='${index}'>
<td><input type="checkbox" ${checked ? 'checked' : ''} /></td>
<td>${index + 1}</td>
<td>${name}</td>
<td>¥${price}</td>
<td>
<button ${count == 1 ? 'disabled' : ''}>-</button>
<span>${count}</span>
<button>+</button>
</td>
<td>¥${price * count}</td>
</tr>`
})
document.querySelector('tbody').innerHTML = products_el.join('')
// 难点1: + 和 -
// 思路1: 查询所有的按钮, 遍历挨个添加 事件
// 思路2: 委托 -> 只需要给按钮共同的父元素添加事件
const tbody = document.querySelector('tbody')
tbody.onclick = function (e) {
// 过滤出按钮的点击
if (e.target.localName == 'button') {
console.log(e.target)
// 按钮的 父元素 的 父元素的 自定义属性.index
const index = e.target.parentElement.parentElement.dataset.index
console.log('序号:', index)
// 现在场景: 页面是通过数据数组生成的, 他们应该联动
if (e.target.innerHTML == '+') {
products[index].count++
}
if (e.target.innerHTML == '-') {
products[index].count--
}
console.log(products)
//更新对应序号的界面
updateCell(index)
}
}
// 数据变化后, 要同步更新对应的栏目
function updateCell(index) {
// 通过序号, 从tbody孩子中, 找到对应的一条
const cell = tbody.children[index]
const subtotal = cell.lastElementChild //小计元素
// 数量: 小计上方元素的孩子中的序号1
const count_el = subtotal.previousElementSibling.children[1]
// 从数据数组中, 读取 单价 和 数量
const { count, price } = products[index]
// 把数据 赋值给 元素内容
count_el.innerHTML = count
subtotal.innerHTML = '¥' + price * count
// -按钮
const jian_el = count_el.previousElementSibling
// 数量==1 是true, 则说明 不可用是 true
// jian_el.disabled = count == 1 ? true : false
jian_el.disabled = count == 1
// 更新合计
updateTotal()
}
//合计
function updateTotal() {
// 数组高阶函数: reduce, 合并归纳数组数据
// sum是总和, 0是初始值, value是每次遍历的元素
const total = products.reduce((sum, value) => {
const { price, count, checked } = value
// 只累加 勾选的元素的价格, 此处利用 true1 false0
// 乘以 checked, 如果是false, 不勾选,就是0, 不累加
return sum + price * count * checked
}, 0)
// 获取合计元素
const total_el = document.querySelector('tfoot td')
total_el.innerHTML = '合计: ¥' + total
}
// 初始时: 触发一次总和
updateTotal()
// 全选按钮初始状态: 数组中的每一个都是勾选,则全选真的
const cha = document.querySelector('thead input')
// 忘记的人: 回顾 JSCORE 的day03
cha.checked = products.every(value => value.checked)
// 全选按钮变化时, 让其他勾选都变化
cha.onchange = function () {
//找到其他的所有按钮
const chs = document.querySelectorAll('tbody input')
// 遍历每一项, 让其勾选状态 和 全选按钮的一致
chs.forEach(value => (value.checked = cha.checked))
// 同步更新数据中的 checked
products.forEach(value => (value.checked = cha.checked))
// 重新算总和
updateTotal()
}
// 为每一个单选按钮, 添加change事件:
const chs = document.querySelectorAll('tbody input')
chs.forEach(value => {
value.onchange = function () {
// 获取序号
const index = this.parentElement.parentElement.dataset.index
// 修改对应数据项的checked属性, 与当前选框的 选中状态一样
products[index].checked = this.checked
// 更新总价格
updateTotal()
// 全选按钮要跟随单选变化: 数据中的每一个元素, 都是勾选才是全选
cha.checked = products.every(value => value.checked)
}
})
</script>
</body>
</html>