博客列表 >js模块化操作及购物车案例

js模块化操作及购物车案例

培(信仰)
培(信仰)原创
2021年02月08日 18:59:25606浏览

js模块化操作及购物车案例

购物车案例

先上一个原生js版的

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>购物车</title>
  7. <link rel="stylesheet" href="style.css" />
  8. </head>
  9. <body>
  10. <table>
  11. <caption>
  12. 购物车
  13. </caption>
  14. <thead>
  15. <tr>
  16. <!-- 全选复选框 -->
  17. <th>
  18. <input
  19. type="checkbox"
  20. name="checkAll"
  21. id="check-all"
  22. checked
  23. /><label for="check-all">全选</label>
  24. </th>
  25. <th>图片</th>
  26. <th>品名</th>
  27. <th>单位</th>
  28. <th>单价</th>
  29. <th>数量</th>
  30. <th>金额/元</th>
  31. </tr>
  32. </thead>
  33. <tbody>
  34. <tr>
  35. <td><input type="checkbox" name="item" value="SN-1020" checked /></td>
  36. <td>
  37. <a href=""><img src="images/p1.jpg" alt="" /></a>
  38. </td>
  39. <td>iPhone 11</td>
  40. <td></td>
  41. <td class="price">4799</td>
  42. <td><input type="number" min="1" value="1" /></td>
  43. <td class="amount">***</td>
  44. </tr>
  45. <tr>
  46. <td><input type="checkbox" name="item" value="sn-1020" checked /></td>
  47. <td>
  48. <a href=""><img src="images/p2.jpg" alt="" /></a>
  49. </td>
  50. <td>小米pro 11</td>
  51. <td></td>
  52. <td class="price">3999</td>
  53. <td><input type="number" min="1" value="1" /></td>
  54. <td class="amount">***</td>
  55. </tr>
  56. <tr>
  57. <td><input type="checkbox" name="item" value="SN-1030" checked /></td>
  58. <td>
  59. <a href=""><img src="images/p3.jpg" alt="" /></a>
  60. </td>
  61. <td>MacBook pro</td>
  62. <td></td>
  63. <td class="price">18999</td>
  64. <td><input type="number" min="1" value="1" /></td>
  65. <td class="amount">***</td>
  66. </tr>
  67. <tr>
  68. <td><input type="checkbox" name="item" value="SN-1040" checked /></td>
  69. <td>
  70. <a href=""><img src="images/p4.jpg" alt="" /></a>
  71. </td>
  72. <td>小米75电视</td>
  73. <td></td>
  74. <td class="price">5999</td>
  75. <td><input type="number" min="1" value="1" /></td>
  76. <td class="amount">***</td>
  77. </tr>
  78. <tr>
  79. <td><input type="checkbox" name="item" value="SN-1050" checked /></td>
  80. <td>
  81. <a href=""><img src="images/p5.jpg" alt="" /></a>
  82. </td>
  83. <td>Canon 90D单反</td>
  84. <td></td>
  85. <td class="price">9600</td>
  86. <td><input type="number" min="1" value="1" /></td>
  87. <td class="amount">***</td>
  88. </tr>
  89. </tbody>
  90. <tfoot>
  91. <tr>
  92. <td colspan="5">总计:</td>
  93. <td id="sum">***</td>
  94. <td id="total-amount">***</td>
  95. </tr>
  96. </tfoot>
  97. </table>
  98. <div class="closing-cost">
  99. <button class="cost">结算</button>
  100. </div>
  101. <script>
  102. //1. 获取全选复选框,所有独立商品的复选框
  103. const checkAll = document.querySelector("#check-all");
  104. const checkItems = document.getElementsByName("item");
  105. //2. 为全选复选框添加事件:change,当值改变时触发
  106. checkAll.onchange = (ev) =>
  107. checkItems.forEach((item) => (item.checked = ev.target.checked));
  108. //3. 为每个单独商品的复选框添加change事件
  109. checkItems.forEach(
  110. (item) =>
  111. (item.onchange = () =>
  112. (checkAll.checked = [...checkItems].every((item) => item.checked)))
  113. );
  114. const numbs = document.querySelectorAll("tbody input[type=number]");
  115. numbs.forEach((item) => (onchange = autoCalculate)); //方法赋值给方法不能有()
  116. checkAll.addEventListener("change",autoCalculate);
  117. checkItems.forEach(item => addEventListener("change",autoCalculate));
  118. //购物车刚加载完成时也应该触发自动计算
  119. window.onload = autoCalculate;
  120. function autoCalculate() {
  121. //获取购物车所有商品的单价
  122. const price = document.querySelectorAll("tbody .price");
  123. const priceArr = [...price].map((item) => item.textContent * 1);
  124. //获取购物车所有商品的数量
  125. const numbers = document.querySelectorAll("tbody input[type=number]");
  126. const numbersArr = [...numbers].map((item) => item.value * 1);
  127. //计算每件商品金额
  128. let amountArr = [priceArr, numbersArr].reduce((total, cur) =>
  129. total.map((item, index) => item * cur[index])
  130. );
  131. //获取选中商品数量,使用filter 筛选出 选中的checkbox
  132. const checkedNumbersArr = [...numbersArr].filter(
  133. (item, index) => [...checkItems][index].checked
  134. );
  135. //计算选中商品的总金额
  136. const checkedAmountArr = [...amountArr].filter(
  137. (item, index) => [...checkItems][index].checked
  138. );
  139. //计算商品总数
  140. let sum = checkedNumbersArr.reduce((pre, cur) => pre + cur,0);
  141. //计算总金额
  142. let totalAmount = checkedAmountArr.reduce((prev, cur) => prev + cur,0);
  143. //将计算结果渲染到购物车中
  144. //总数量
  145. document.querySelector("#sum").textContent = sum;
  146. //总金额
  147. document.querySelector("#total-amount").textContent = totalAmount;
  148. //每个商品的金额
  149. let amountTarget = document.querySelectorAll(".amount");
  150. amountTarget.forEach(
  151. (item, index) => (item.textContent = amountArr[index])
  152. );
  153. }
  154. </script>
  155. </body>
  156. </html>

有个奇怪的点:checkItems.forEach(item => addEventListener("change",autoCalculate));
此条语句注释程序也可以正常运行。

此处全勾选和全不勾选使用 数组的 every很巧妙;使用filter过滤出已选中的商品的数组,进行数量和金额累加也很赞。
reduce方法真的很强大,再次赞叹。

jQuery版购物车

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>购物车</title>
  7. <link rel="stylesheet" href="style.css" />
  8. </head>
  9. <body>
  10. <table>
  11. <caption>
  12. 购物车
  13. </caption>
  14. <thead>
  15. <tr>
  16. <!-- 全选复选框 -->
  17. <th>
  18. <input
  19. type="checkbox"
  20. name="checkAll"
  21. id="check-all"
  22. checked
  23. /><label for="check-all">全选</label>
  24. </th>
  25. <th>图片</th>
  26. <th>品名</th>
  27. <th>单位</th>
  28. <th>单价</th>
  29. <th>数量</th>
  30. <th>金额/元</th>
  31. </tr>
  32. </thead>
  33. <tbody>
  34. <tr>
  35. <td><input type="checkbox" name="item" value="SN-1020" checked /></td>
  36. <td>
  37. <a href=""><img src="images/p1.jpg" alt="" /></a>
  38. </td>
  39. <td>iPhone 11</td>
  40. <td></td>
  41. <td class="price">4799</td>
  42. <td><input type="number" min="1" value="1" /></td>
  43. <td class="amount">***</td>
  44. </tr>
  45. <tr>
  46. <td><input type="checkbox" name="item" value="sn-1020" checked /></td>
  47. <td>
  48. <a href=""><img src="images/p2.jpg" alt="" /></a>
  49. </td>
  50. <td>小米pro 11</td>
  51. <td></td>
  52. <td class="price">3999</td>
  53. <td><input type="number" min="1" value="1" /></td>
  54. <td class="amount">***</td>
  55. </tr>
  56. <tr>
  57. <td><input type="checkbox" name="item" value="SN-1030" checked /></td>
  58. <td>
  59. <a href=""><img src="images/p3.jpg" alt="" /></a>
  60. </td>
  61. <td>MacBook pro</td>
  62. <td></td>
  63. <td class="price">18999</td>
  64. <td><input type="number" min="1" value="1" /></td>
  65. <td class="amount">***</td>
  66. </tr>
  67. <tr>
  68. <td><input type="checkbox" name="item" value="SN-1040" checked /></td>
  69. <td>
  70. <a href=""><img src="images/p4.jpg" alt="" /></a>
  71. </td>
  72. <td>小米75电视</td>
  73. <td></td>
  74. <td class="price">5999</td>
  75. <td><input type="number" min="1" value="1" /></td>
  76. <td class="amount">***</td>
  77. </tr>
  78. <tr>
  79. <td><input type="checkbox" name="item" value="SN-1050" checked /></td>
  80. <td>
  81. <a href=""><img src="images/p5.jpg" alt="" /></a>
  82. </td>
  83. <td>Canon 90D单反</td>
  84. <td></td>
  85. <td class="price">9600</td>
  86. <td><input type="number" min="1" value="1" /></td>
  87. <td class="amount">***</td>
  88. </tr>
  89. </tbody>
  90. <tfoot>
  91. <tr>
  92. <td colspan="5">总计:</td>
  93. <td id="sum">***</td>
  94. <td id="total-amount">***</td>
  95. </tr>
  96. </tfoot>
  97. </table>
  98. <div class="closing-cost">
  99. <button class="cost">结算</button>
  100. </div>
  101. <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
  102. <script>
  103. //1. 获取全选复选框,所有独立商品的复选框
  104. const checkAll = $("#check-all");
  105. const checkItems = $("input[name=item]");
  106. //2. 为全选复选框添加事件:change,当值改变时触发
  107. checkAll.change((ev) =>
  108. checkItems.each(function () {
  109. $(this).prop("checked", $(ev.target).is(":checked"));
  110. })
  111. );
  112. //3. 为每个单独商品的复选框添加change事件
  113. checkItems.change(() => {
  114. checkAll.prop(
  115. "checked",
  116. [...checkItems].every((item) => $(item).checked)
  117. );
  118. });
  119. $("tbody input[type=number]").each((index, item) =>
  120. $(item).change(autoCalculate)
  121. );
  122. // 改变独立复选框状态时触发
  123. $("input[name=item]").each((index, item) => $(item).change(function(){
  124. autoCalculate();
  125. }));
  126. // 全选状态改变时触发
  127. $('#check-all').change(function(){
  128. autoCalculate();
  129. });
  130. // 页面载入完成后触发
  131. $(function () {
  132. autoCalculate();
  133. });
  134. //购物车刚加载完成时也应该触发自动计算
  135. window.onload = autoCalculate;
  136. function autoCalculate() {
  137. //获取购物车所有商品的单价
  138. let priceArr = $("tbody .price").map(
  139. (index, item) => $(item).text() * 1
  140. );
  141. //获取购物车所有商品的数量
  142. let numbersArr = $("input[type=number]").map(
  143. (index, item) => $(item).val() * 1
  144. );
  145. //计算每件商品金额
  146. let amountArr = [priceArr, numbersArr].reduce((total, cur) =>
  147. total.map((index, item) => item * cur[index])
  148. );
  149. //获取选中商品数量,使用filter 筛选出 选中的checkbox
  150. let checkedNumbersArr = numbersArr.filter((index, item) =>
  151. $(checkItems[index]).is(":checked")
  152. );
  153. //计算选中商品的总金额
  154. let checkedAmountArr = amountArr.filter((index, item) =>
  155. $(checkItems[index]).is(":checked")
  156. );
  157. //计算商品总数
  158. let sum = [...checkedNumbersArr].reduce((pre, cur) => pre + cur);
  159. //计算总金额
  160. let totalAmount = [...checkedAmountArr].reduce(
  161. (prev, cur) => prev + cur
  162. );
  163. console.log(sum);
  164. //将计算结果渲染到购物车中
  165. //总数量
  166. $("#sum").text(sum);
  167. //总金额
  168. $("#total-amount").text(totalAmount);
  169. //每个商品的金额
  170. $(".amount").each((index, item) => $(item).text(amountArr[index]));
  171. }
  172. </script>
  173. </body>
  174. </html>

效果相同,不同点也很明显先比之下,个人还是觉得原生的写起来要顺手很多。jQ中方法很强大,吐槽点可能是不太熟练的原因,经常忘记jq中的参数和原生是反的。比如filter,map等。回头看时才了然。希望以后用的熟练了可以避免这种低级错误。

模块的知识

  1. 模块就是一个js代码块
  2. 封装成模块的js文件,内部成员对外不见,除非导出来
  3. 模块解决了js的模块化开发与代码封装问题

模块解决了什么问题

  1. 可扩展性: 每个模块是独立的,各写各的互不影响,出错直接定位责任人
  2. 可复用性: 只需要一条import 指令就可以导入
  3. 避免污染全局空间:模块处在自己的命名空间内

模块是一个js文件,显示不能像之前一样,将js代码写到html中
模块要写到一个独立的js文件中,并使用一些特别的语法和关键字

那怎么写呢?

  1. <script type="module">
  2. // 第二步 使用 import {和模块中的导出变量一致} from "需要导入的模块路径"
  3. // 路径前面的 ./ 不能省略 import 必须放在首行
  4. import { userName, hello, User } from "./module1.js";
  5. console.log(userName);
  6. console.log(hello(userName));
  7. let user = new User("Mac book", 18999);
  8. console.log(user.print());
  9. //1. 禁止重复声明模块成员
  10. // let userName;
  11. //2. 模块成员也不允许更新
  12. // userName = "phone";
  13. //模块成员在当前作用域相当于常量
  14. </script>

注意:一定要先在script 标签中 申明type=”module”

js文件中必须要有export导出,导出可以分别导出和统一导出

例如:module1.js文件

  1. // // 分别到导出
  2. // export let userName = 'I';
  3. // export function hello(userName) {
  4. // return `Hello PHP,${userName} have a dream.`;
  5. // }
  6. // export class User {
  7. // constructor(name,price){
  8. // this.name=name;
  9. // this.price=price;
  10. // }
  11. // print(){
  12. // return this.name +" => " +this.price;
  13. // }
  14. // }
  15. // //没有export 关键字是私有成员,外部不能访问
  16. // let salary = 123;
  17. // 还可以统一导出
  18. let userName = 'I';
  19. function hello(userName) {
  20. return `Hello PHP,${userName} have a dream.`;
  21. }
  22. class User {
  23. constructor(name,price){
  24. this.name=name;
  25. this.price=price;
  26. }
  27. print(){
  28. return this.name +" => " +this.price;
  29. }
  30. }
  31. //推荐使用方法
  32. export {userName,hello,User}

导入时可以使用别名导入,这样就不担心重名了。

  1. // 别名导入
  2. import {myName as userName,echo} from "./module2.js"

还可以使用别名导出

例如可以在module的js文件中使用

  1. export {userName as myName,hello as echo,User as FirstUser}

如果只有一个默认成员导出时可以不加大括号

  1. let userName = "I";
  2. function hello(userName) {
  3. return `Hello PHP,${userName} have a dream.`;
  4. }
  5. class User {
  6. constructor(name, price) {
  7. this.name = name;
  8. this.price = price;
  9. }
  10. print() {
  11. return this.name + " => " + this.price;
  12. }
  13. }
  14. //默认导出的成员不要加大括号
  15. // export default hello;
  16. //导出列表中既有默认成员,又有普通成员 怎么做
  17. //email 是非静态成员
  18. let email = "admin@php.cn";
  19. //认为hello是默认成员
  20. export { userName, email, hello as default };
  1. <script type="module">
  2. // 导入默认模块与普通模块的最大区别在于没有大括号
  3. // import userName from "./module3.js";
  4. // console.log(userName);
  5. // import hello from "./module3.js";
  6. // console.log(hello("I"));
  7. // 既有默认成员,又有普通成员
  8. import hello, {email} from "./module3.js"
  9. console.log(email);
  10. console.log(hello("有default又有普通成员"));
  11. </script>

还可以使用命名空间的方法

  1. <script type="module">
  2. //命名空间:是一个容器,内部可以包括任何类型的数据
  3. //命名空间是一个对象,可以挂载到当前的全局中
  4. // let ns ={
  5. // a:1,b:2,c:3
  6. // }
  7. //ns:就是一个
  8. // console.log(ns.a,ns.b,ns.c);
  9. import * as namespace from "./module1.js";
  10. let userName;
  11. let hello = () => {};
  12. class User {};
  13. console.log(namespace);
  14. console.log(namespace.userName);
  15. console.log(namespace.hello(namespace.userName));
  16. console.log(new namespace.User("Mac book",18999).print());
  17. </script>

使用命名空间好处明显:层次清晰,有效减少命名冲突。

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议