Blogger Information
Blog 32
fans 0
comment 0
visits 22170
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
js模块化操作及购物车案例
培(信仰)
Original
604 people have browsed it

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>

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

Correcting teacher:天蓬老师天蓬老师

Correction status:qualified

Teacher's comments:
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post