购物车商品全选和金额计算案例
table {
border-collapse: collapse;
width: 90%;
text-align: center;
margin: auto;
}
table caption {
margin-bottom: 15px;
font-size: 1.5rem;
}
table th,
table td {
border-bottom: 1px solid #ccc;
padding: 5px;
font-weight: normal;
}
table thead tr:first-of-type {
background-color: #e6e6e6;
height: 3em;
}
table input[type="checkbox"] {
width: 1.5em;
height: 1.5em;
}
table tbody tr {
border-bottom: 1px solid #ccc;
}
table tbody tr:hover {
background-color: #f6f6f6;
cursor: pointer;
}
tbody img {
width: 3em;
}
tbody input[type="number"] {
width: 3em;
}
button {
width: 150px;
height: 30px;
outline: none;
border: none;
background-color: teal;
color: white;
letter-spacing: 5px;
}
button:hover {
opacity: 0.7;
cursor: pointer;
}
<table>
<caption>
购物车
</caption>
<thead>
<tr>
<!-- 全选复选框 -->
<th><input type="checkbox" name="checkAll" id="check-all" checked /><label for="check-all">全选</label></th>
<th>图片</th>
<th>品名</th>
<th>单位</th>
<th>单价/元</th>
<th>数量</th>
<th>金额/元</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="checkbox" name="item" value="SN-1020" checked />
</td>
<td>
<a href=""><img src="images/p1.jpg" alt="" /></a>
</td>
<td>iPhone 11</td>
<td>台</td>
<td class="price">4799</td>
<td><input type="number" min="1" value="1" /></td>
<td class="amount">4799</td>
</tr>
<tr>
<td>
<input type="checkbox" name="item" value="SN-1020" checked />
</td>
<td>
<a href=""><img src="images/p2.jpg" alt="" /></a>
</td>
<td>小米pro 11</td>
<td>部</td>
<td class="price">3999</td>
<td><input type="number" min="1" value="2" /></td>
<td class="amount">7998</td>
</tr>
<tr>
<td>
<input type="checkbox" name="item" value="SN-1030" checked />
</td>
<td>
<a href=""><img src="images/p3.jpg" alt="" /></a>
</td>
<td>MacBook Pro</td>
<td>台</td>
<td class="price">18999</td>
<td><input type="number" min="1" value="1" /></td>
<td class="amount">18999</td>
</tr>
<tr>
<td>
<input type="checkbox" name="item" value="SN-1040" checked />
</td>
<td>
<a href=""><img src="images/p4.jpg" alt="" /></a>
</td>
<td>小米75电视</td>
<td>台</td>
<td class="price">5999</td>
<td><input type="number" min="1" value="2" /></td>
<td class="amount">11998</td>
</tr>
<tr>
<td>
<input type="checkbox" name="item" value="SN-1050" checked />
</td>
<td>
<a href=""><img src="images/p5.jpg" alt="" /></a>
</td>
<td>Canon 90D单反</td>
<td>台</td>
<td class="price">9699</td>
<td><input type="number" min="1" value="1" /></td>
<td class="amount">9699</td>
</tr>
</tbody>
<tfoot>
<tr style="font-weight: bolder; font-size: 1.2em">
<td colspan="5">总计:</td>
<td id="sum">7</td>
<td id="total-amount">53493</td>
</tr>
</tfoot>
</table>
<div style="width: 90%; margin: 10px auto">
<button style="float: right; width: 100px">结算</button>
</div>
// 1.获取全选按钮,每个独立的商品复选框
const checkAll = document.querySelector('#check-all');
const checkItems = document.getElementsByName("item");
// 2. 将当前的全选的状态变化赋值给每个商品复选框
checkAll.addEventListener('change', (ev) => {
checkItems.forEach(item => {
item.checked = ev.target.checked
});
// 根据选中状态计算商品的总金额和总数量
amountTotal();
});
// 3. 为每个单独商品的复选框添加事件
checkItems.forEach(item => {
item.addEventListener('change', () => {
checkAll.checked = [...checkItems].every(item => item.checked);
// 根据选中状态计算商品的总金额和总数量
amountTotal();
})
});
// 4.为数量按钮添加事件,动态计算商品总量和金额
const numInput = document.querySelectorAll('tbody input[type="number"]');
numInput.forEach(input => input.addEventListener('change', autoCalculate));
// 页面加载完成自动计算
window.addEventListener('load', autoCalculate);
// 5. 自动计算方法
function autoCalculate() {
// 获取所有商品单价节点
const prices = document.querySelectorAll('tbody .price');
// 获得所有商品单价金额
const priceArr = [...prices].map(price => +price.innerText);
console.log(priceArr);
// 获取所有数量按钮节点
const numbers = document.querySelectorAll('tbody input[type="number"]');
// 获得所有商品数量数组
const numArr = [...numbers].map(num => +num.value);
console.log(numArr);
// 计算单个商品金额 = 数量*单价
let amountArr = [priceArr, numArr].reduce((total, curr) => {
return total.map((item, index) => {
return item * curr[index]
})
});
// 将每一个商品金额渲染到页面中
document.querySelectorAll('.amount').forEach((item, index) => {
item.innerText = amountArr[index]
})
// 计算总数量总数量
amountTotal();
}
// 根据复选框选中状态计算总金额和总数量
function amountTotal() {
// 获取所有数量按钮节点
const numbers = document.querySelectorAll('tbody input[type="number"]');
// 获得所有商品数量数组
const numArr = [...numbers].map(num => {
// 获取当前数量节点父节点下的check复选框
const check = num.parentElement.parentElement.querySelector('input[type="checkbox"]');
// 过滤出选中的商品数量数组
return check.checked ? +num.value : 0;
});
console.log(numArr);
// 获取所有单个商品总金额节点
const amounts = document.querySelectorAll('.amount');
// 获得所有单个商品总金额数组
const amountArr = [...amounts].map(amount => {
// 获取当前数量节点父节点下的check复选框
const check = amount.parentElement.querySelector('input[type="checkbox"]');
// 过滤出选中的商品数量数组
return check.checked ? +amount.innerText : 0;
});
console.log(amountArr);
// 计算总数量
document.querySelector('#sum').innerText = `${numArr.reduce((pre, cur) => pre + cur)}件`;
// 计算总金额
document.querySelector('#total-amount').textContent = `¥${amountArr.reduce((pre, curr) => pre + curr)}`;
}
实现效果:
预览地址:http://easys.ltd/shopcart/
ES6的模块化实现
一个模块就是一个独立的js代码块文件,下面将介绍module中的export和import概念。
ES6 module 模块功能使用 export 导出模块的内容,并使用 import 导入模块的内容。
示例:
// math.js(定义模块)
exports.add = function(a, b) {
return a + b;
};
// app.js(使用模块)
var math = require('./math');
var rs = math.add(1, 2);
console.log(rs);
(导出)export用于规定模块的对外接口
创建ES6模块时,可使用export关键字导出(对外提供)模块的内容,如函数、对象以及原始变量等等。
export 导出方案有2种:Named exports(命名导出;每个模块可有多个)和 Default exports(默认导出;每个模块只能一个)。
Named exports 命名导出
说明:使用 export + 名称 的形式导出模块的内容。
注意:在 import 导入过程中,需指定这些名称。
// 1) 声明时导出
export let myVar = 'a';
export const MY_CONST = 'c';
export const getName = () => {}...
export const getAge = () => {}...
export function getName(){
return ...
}
// 2) 声明后导出
var myVar = 'a';
export const MY_CONST = 'c';
const getName = () =>{} ...
const getAge = () =>{} ...
export {myVar,MY_CONST,getName,getAge}
// 3) 别名导出
var myVar3 = 'a';
export { myVar3 as myVar };
// math.js
export function add(a, b) {
return a + b;
}
// app.js:导入含有命名导出的模块时,需要指定成员名称
import { add } from './math.js';
console.log(add(1, 2)); // => 3
Default exports 默认导出
说明:使用 export default 导出模块默认的内容,每个模块只能有一个 export default。
// 1) 声明时导出 匿名函数
export default expression;
export default function() {
return ...
}
export default () => {}...
// 2) 别名设置为default导出
export default function name1() {}
export { name1 as default };
默认导出声明的是一个表达式,通常没有名字,导入时需指定模块名称。
// math.js
export function add(a, b) {
return a + b;
}
export default function cube(x) {
return x * x * x;
}
// app.js:导入默认导出的模块时,需要指定模块名称
import cube from './math.js';
console.log(cube(3)); // => 27
// 若想同时导入含有默认导出、命名导出的模块,只需要导入时用','隔开
import cube, { add } from './math.js';
(导入)import用于输入其他模块提供的功能
// 1)导入模块的默认导出内容
import defaultExport from 'module-name';
// 2)导入模块的命名导出内容
import { export1, export2 } from 'module-name';
import { export as alias } from 'module-name'; // 修改别名
import * as name from 'module-name'; // 导入模块内的所有命名导出内容
// 3)导入模块的默认导出、命名导出
import defaultExport, { export1, export2 } from 'module-name';
import defaultExport, * as name from 'module-name';
1) 导入默认导出
说明:导入默认导出的模块时,需要指定模块名称
// math.js
export default function cube(x) {
return x * x * x;
}
// app.js:导入默认导出的模块时,需要指定模块名称
import cube from './math.js';
console.log(cube(3)); // => 27
import user from './default.js' // 如果使用这种引入请导出匿名函数
2) 导入命名导出
说明:导入模块时可使用大括号包含指定命名成员;也可以用 * as moduleName 的形式把此模块的所有命名导出作为某个对象的成员。
// math.js
export function add(a, b) {
return a + b;
}
// app.js:指定使用math模块的add命名导出
import { add } from './math.js';
console.log(add(1, 2)); // => 3
// 按需引入
import { getName, getAge } from './utils.js'
// 导入所有的命名导出作为math对象的成员
import * as math from './math.js';
console.log(math.add(1, 2)); // => 3
// 将引入的模块赋值到user对象中
import * as user from './utils.js'
// 结构会变成如下样式
// user = {
// getAge: function(){ ... }
// getName: function(){ ... }
// }
3) 仅导入模块
说明:仅导入模块时,只会执行模块的全局函数,不会导入任何成员。
// math.js
export function add(a, b) {
return a + b;
}
function hello() {
console.log('hello math.js');
}
hello();
// app.js
import { add } from './math.js'; // => hello math.js
注意:模块成员在当前使用环境中,既不能重复声明,也不能更新(相对应常量)