PHP 学习之路:第十五天—— 购物车实战与模块简介

197 阅读3分钟

购物车基本样式

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));

image.png

// 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,就不要参与到计算中

三、模板的知识

什么是模块?

  1. 模块就是一个单独的 js 代码块
  2. 封装成模块的 js 文档,内部成员外部不可见,除非导出
  3. 模块解决了模块化编程与代码封闭的问题
<!-- 传统方式 -->
<!-- <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 };