购物车基本样式
html 文件:
<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>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>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>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>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>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>
css 文件:
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;
}
一、购物车的全选
- Array.every(callback):每个成员经回调处理后,全部为true,才最终返回true,否则为false, 与
- Array.some(callback):每个成员经回调处理后,只要有一个为true,最终返回就是true , 或
// array.every(): 每个成员经回调处理后,全部为true,才最终返回true,否则为false, 与
console.log([5, 6, 7, 8].every(item => item > 6));
console.log([5, 6, 7, 8].every(item => item > 4));
// array.some(): 每个成员经回调处理后,只要有一个为true,最终返回就是true , 或
console.log([5, 6, 7, 8].some(item => item >= 8));
console.log([5, 6, 7, 8].some(item => item > 10));
// 1. 获取全选按钮 , 每个独立 的商品复选框
const checkAll = document.querySelector("#check-all");
const checkItems = document.getElementsByName("item");
// 2. 将当前全选的状态变化赋值给每个商品
checkAll.onchange = (ev) => checkItems.forEach((item) => (item.checked = ev.target.checked));
// 3. 为每个单独的商品复选框添加change
// [...checkItems].every((item) => item.checked: 返回的是布尔值
checkItems.forEach(
(item) => (item.onchange = () => (checkAll.checked = [...checkItems].every((item) => item.checked)))
);
二、购物车自动计算
// 1. 获取全选按钮 , 每个独立 的商品复选框
const checkAll = document.querySelector("#check-all");
const checkItems = document.getElementsByName("item");
// 2. 将当前全选的状态变化赋值给每个商品
checkAll.onchange = (ev) => checkItems.forEach((item) => (item.checked = ev.target.checked));
// 3. 为每个单独的商品复选框添加change
// [...checkItems].every((item) => item.checked: 返回的是布尔值
checkItems.forEach(
(item) => (item.onchange = () => (checkAll.checked = [...checkItems].every((item) => item.checked)))
);
// ==============================================================
// 数量控件
const numInput = document.querySelectorAll('tbody input[type="number"]');
// 用户更新数量时自动计算
numInput.forEach((input) => (onchange = autoCalculate));
// 页面加载完成后自动计算
window.onload = autoCalculate;
// 自动计算方法
function autoCalculate() {
// 单价数组
const prices = document.querySelectorAll("tbody .price");
// forEach()没有返回值,这里用一个和它一样功能的方法: map(), 功能一样,但有返回值
// const priceArr = [...prices].map((price) => Number(price.textContent));
const priceArr = [...prices].map((price) => price.textContent * 1);
// 数量数组
const numbers = document.querySelectorAll("tbody input[type=number]");
const numArr = [...numbers].map((num) => num.value * 1);
// 商品总数
let sum = numArr.reduce((pre, cur) => pre + cur);
// 计算金额: 数量 * 单价 = 金额
const amountArr = [priceArr, numArr].reduce((total, curr) => total.map((item, index) => item * curr[index]));
// 将计算结果渲染到页面中
// 总数量
// document.querySelector("#sum").textContent = `${sum}`;
document.querySelector("#sum").textContent = String(sum);
// 将每个商品的金额填充进去
document.querySelectorAll(".amount").forEach((item, index) => (item.textContent = amountArr[index]));
// 总金额
document.querySelector("#total-amount").textContent = String(amountArr.reduce((pre, curr) => pre + curr));
}
// 思考问题: 让购物车的自动计算依赖于每个商品的复选框的选中状态
// 只需要重新计算总金额和总数量,每个商品的金额不要重新计算
// 1. 思路: 为每个商品复选框加change,当change为false时自动计算总金额和总数量
// 2. 思路: 在获取数量,金额 之前,就要考虑到每个商品的复选框的状态,如果为false,就不要参与到计算中
三、模板的知识
什么是模块?
- 模块就是一个单独的 js 代码块
- 封装成模块的 js 文档,内部成员外部不可见,除非导出
- 模块解决了模块化编程与代码封闭的问题
<!-- 传统方式 -->
<!-- <script src="module1.js"></script> -->
<script type="module">
// import { userName } from "./module1.js";
import { userName, hello, User } from "./module1.js";
console.log(userName);
console.log(hello(userName));
let user = new User("外衣", 999);
console.log(user.print());
// let userName = "aaa";
// userName = "aaa";
// 模块成员在当前使用环境中,即不能重复声明,也不能更新
// 一句话,模块成员就是当前环境中的“常量”
</script>
module1.js 中文件:
let userName = "朱老师";
// export let userName = "朱老师";
// export { userName };
// export function hello(name) {
// return "Hello " + name;
// }
function hello(name) {
return "Hello " + name;
}
class User {
constructor(name, price) {
this.name = name;
this.price = price;
}
print() {
return `${this.name} : ${this.price} 元`;
}
}
export { userName, hello, User };
四、别名导入
<script type="module">
// 导入指令要放在最前事
import { userName as myName } from "./module1.js";
let userName = "欧阳老师";
console.log(userName);
// 此时用别名访问模块导入的成员
console.log(myName);
</script>
module1.js 中文件:
let userName = "朱老师";
// export let userName = "朱老师";
// export { userName };
// export function hello(name) {
// return "Hello " + name;
// }
function hello(name) {
return "Hello " + name;
}
class User {
constructor(name, price) {
this.name = name;
this.price = price;
}
print() {
return `${this.name} : ${this.price} 元`;
}
}
export { userName, hello, User };
五、默认导出
<script type="module">
import hello, { userName } from "./module2.js";
console.log(hello("张帅"));
console.log(hello(userName));
</script>
module2.js 中文件:
// 默认模块
// 一个模块中只允许有一个默认成员导出
let userName = "朱老师";
function hello(name) {
return "Hello " + name;
}
// 默认模块不能加大括号
// export default hello;
// 并非是说只能有一个导出成员,只是有导出成员中,只允许有一个是默认成员
export { userName, hello as default };
六、模块的命名空间
<script type="module">
// import { userName, hello, User } from "./module1.js"
// 如果导入的成员非常多,那么就很可能会和当前空间的成员产生命名冲突
// 此时,可以为这此导入的外部成员的集合,设置一个挂载点
// 命名空间只是一个合法的标识符就可以
// js只支持四种字符: 英文字母,数字, 下划线, $, 并且不能以数字开始
import * as phpcn from "./module1.js";
console.log(phpcn.userName);
console.log(phpcn.hello("aaaa"));
let userObj = new phpcn.User("汽车", 90000);
console.log(userObj.print());
// function hello() {}
// console.log(userName, hello("aaa"));
// let user = new User("外衣", 999);
// console.log(user.print());
</script>
module1.js 中文件:
let userName = "朱老师";
// export let userName = "朱老师";
// export { userName };
// export function hello(name) {
// return "Hello " + name;
// }
function hello(name) {
return "Hello " + name;
}
class User {
constructor(name, price) {
this.name = name;
this.price = price;
}
print() {
return `${this.name} : ${this.price} 元`;
}
}
export { userName, hello, User };