Blogger Information
Blog 29
fans 1
comment 0
visits 35391
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
使用原生 js 完成一个购物车页面和 ES6 中模块的导入问题
祥子弟弟
Original
1154 people have browsed it

一、实现一个购物车

购物车要实现的功能

  1. 全选框选中时,底下的单个商品复选框按钮要全部选中

  2. 单个商品复选框中只要有一个没有被选中,则全选复选框取消选中

  3. 改变商品数量的时候,后边的金额会自动进行加减

  4. 总价和总数量中只计算当前勾选的商品,但是没有勾选的商品中数量和金额可以变动

整个购物车的简陋样子如下:

先完成功能 1,2(功能 1,2 后边会和 3,4 进行一下合并)

首先要做的就是拿到全选复选框和全部的单选复选框,然后对复选框添加 “change” 事件。完成 1,2 功能

  1. // 1.获取全选复选框,所有单品的复选框
  2. const checkAll = document.querySelector("#check-all");
  3. // console.log(checkAll);
  4. const checkItems = document.querySelectorAll('input[name="item"]');
  5. // console.log(checkItems);
  6. // 2.为全选复选框按钮添加事件:change,当前值改变会触发事件
  7. checkAll.onchange = (ev) => {
  8. // console.log(ev.target.checked);
  9. // 当全选复选框是checked时,对每个单品复选框都要进行checked选中
  10. checkItems.forEach((item) => (item.checked = ev.target.checked));
  11. };
  12. // 为每个单独的复选框添加事件:change
  13. checkItems.forEach(
  14. // 对单个复选框状态进行判断,如果有一个不为checked状态,则全选复选框不选中
  15. (item) =>
  16. (item.onchange = () =>
  17. (checkAll.checked = [...checkItems].every((item) => item.checked)))
  18. );
  19. // 使用jQuery完成上边的内容,逻辑思路和原生js相同
  20. $("#check-all").on("change", (ev) => {
  21. // 对全选复选框添加change事件
  22. // 当全选复选框的值改变时,对所有的单品复选框进行同步更新它的选中情况
  23. $('input[name="item"]').each(function () {
  24. // change事件发生时,对每个单品的选中情况进行同步
  25. this.checked = ev.target.checked;
  26. });
  27. });
  28. $('input[name="item"]').each(function () {
  29. // 对每个单品的复选框添加change事件
  30. // 对这个单品复选框集合的checked情况进行every()筛选,
  31. // 当所有的单品复选框都选中时,匹配全选复选框
  32. this.onchange = function () {
  33. // console.log($("#check-all")[0].checked);
  34. // console.log([...$('input[name="item"]')]);
  35. $("#check-all")[0].checked = [...$('input[name="item"]')].every(
  36. (item) => item.checked
  37. );
  38. };
  39. });

效果如图

接下来完成功能 3,4,将功能 3,4 涉及到的内容写到一个函数中,因为 3,4 中的功能涉及到功能 1,2,所以后边还需要做一次整合

  1. // 自动计算函数
  2. function autoCalculate() {
  3. // 对后边数量以及单价,总计进行自动计算
  4. // 需要获取到所有的数量,以及所有的单价
  5. // 因为拿到的数据都是string,所以需要想办法转换成数值
  6. // const prices = document.querySelectorAll(".price");
  7. // 因为数据进行运算的时候是会发生类型转换的,所以可以直接进行转换它
  8. // 也可以使用parseInt()方法,将字符串转为数值
  9. // 获取到当前的单价数组,为后面的计算金额
  10. const priceArr = [...document.querySelectorAll(".price")].map(
  11. (item) => item.textContent * 1
  12. );
  13. // console.log(priceArr);
  14. // 获取到被选中事件的索引值
  15. // const checkedArr = [];
  16. // [...checkItems].forEach((ev, index) => {
  17. // if (ev.checked === true) {
  18. // checkedArr.push(index);
  19. // }
  20. // });
  21. // console.log(checkedArr);
  22. // const numbers = document.querySelectorAll('input[type="number"]');
  23. // console.log(numbers[0].value);
  24. // 对商品的复选框状态进行判断,从而获取商品的总数和总金额
  25. // 对当前的数量数组进行获取
  26. const numArr = [...document.querySelectorAll('input[type="number"]')].map(
  27. (item) => item.value * 1
  28. );
  29. // console.log(numArr);
  30. // 使用filter()方法,以当前价格的复选框状态作为判断条件,获取到所有的checked为true的单价
  31. const checkedPrice = priceArr.filter(
  32. (item, index) => [...checkItems][index].checked
  33. );
  34. // console.log(totalPrice);
  35. // 获取到所有checked为true的数量
  36. const checkedNum = numArr.filter(
  37. (item, index) => [...checkItems][index].checked
  38. );
  39. // console.log(totalNum);
  40. // 商品总数的获取,可以使用reduce()方法进行累加操作
  41. // console.log(numArr.reduce((pre, cur) => pre + cur));
  42. // 当reduce()中的参数值为空时,reduce()方法会报错,所以需要进行判断
  43. let sum = 0;
  44. if (checkedNum.length !== 0) {
  45. sum = checkedNum.reduce((pre, cur) => pre + cur);
  46. }
  47. // 计算商品的金额:单价 * 数量,还是使用reduce()方法进行计算
  48. // 商品的金额是不随复选框的变动而变动的,它只和数量的变动相关
  49. const amountArr = [priceArr, numArr].reduce((total, curr) =>
  50. total.map((item, index) => item * curr[index])
  51. );
  52. // 计算已选中商品的金额数组
  53. const checkedAmount = amountArr.filter(
  54. (item, index) => [...checkItems][index].checked
  55. );
  56. // console.log(checkedAmount);
  57. // console.log(amount);
  58. // 计算已选中商品的总金额
  59. let totalAmount = 0;
  60. if (checkedAmount.length !== 0) {
  61. totalAmount = checkedAmount.reduce((pre, cur) => pre + cur);
  62. }
  63. // console.log(totalAmount);
  64. // 将计算结果渲染到购物车中
  65. // 总数量
  66. document.querySelector("#sum").textContent = sum;
  67. // 总金额
  68. document.querySelector("#total-amount").textContent = totalAmount;
  69. // 每个商品的金额
  70. // 根据当前商品的索引和amountArr商品价格数组的索引对应,然后填充到内容中
  71. document
  72. .querySelectorAll(".amount")
  73. .forEach((item, index) => (item.textContent = amountArr[index]));
  74. }
  75. // 获取到所有的数量控件
  76. const numInput = document.querySelectorAll('input[type="number"]');
  77. // console.log(numInput);
  78. // 用户更新数量时触发自动计算,添加change事件
  79. numInput.forEach((ev) => (ev.onchange = autoCalculate));
  80. // 刚加载时,也应该触发自动计算事件
  81. window.onload = autoCalculate;
  82. // 在这块儿对前边的复选框功能做了一下整合,所以只需要这一段代码就好,前边的可以注释掉
  83. // 当取消单个选中时,触发计算事件
  84. checkItems.forEach((item) =>
  85. item.addEventListener("change", function () {
  86. checkAll.checked = [...checkItems].every((item) => item.checked);
  87. autoCalculate();
  88. })
  89. );
  90. // 当全选复选框值发生变动时,自动计算被触发
  91. checkAll.addEventListener("change", function (ev) {
  92. checkItems.forEach((item) => (item.checked = ev.target.checked));
  93. autoCalculate();
  94. });

因为要完成功能 3,4,涉及到功能 1,2 中的复选框的 change 事件,所以进行了整合,前边功能 1,2 的代码可以注释掉

完成的效果图如下

二、ES6 中模块导入问题

首先要知道什么是模块?模块就是一个 js 代码块。一个封装成模块的 js 文件,内部成员对外不见,除非导出来。模块要写到一个独立 的 js 文件中,并使用一些特别的语法和关键字

其次是模块解决了什么问题?

  1. 可维护性: 每个模块是独立的,各写各个互不影响,出错直接定位责任人

  2. 可复用性: 只需要一条 import 指令就可以导入

  3. 避免污染全局空间: 模块处在自己的命名空间内

  4. 模块解决了 js 的模块化开发与代码封装问题

模块的导入

在 ES6 之前的模块导入方式是利用 script 标签的 src 属性

  1. <script src="module1.js"></script>

ES6 之后的模块导入方式

  1. <!-- 导入模块时,必须让type类型为module -->
  2. <script type="module">
  3. // 导入语句,import
  4. // 前面的./不能省略
  5. import { userName, hello, User } from "./module1.js";
  6. </script>

在模块中将想要对外部访问的成员前边加上export关键字,就可以在需要导入的地方使用 import 语句进行导入,除了单个的成员前边加上export关键字之外,还可以对需要导出的所有成员进行统一导出

  1. // 导出语句 export
  2. // export let userName = "小红";
  3. let userName = "小红";
  4. function hello(name) {
  5. return "Hello" + name;
  6. }
  7. class User {
  8. constructor(name, age) {
  9. this.name = name;
  10. this.age = age;
  11. }
  12. show() {
  13. return this.name + "今年" + this.age + "了";
  14. }
  15. }
  16. // 模块中的私有成员,不能被外部访问
  17. let gender = "男";
  18. // 统一导出
  19. export { userName, hello, User };

导入模块之后就可以去使用模块中定义的成员了。

模块中的别名导出导入

为什么要进行别名导入呢?因为有时候会在当前作用域中定义和模块中同名的变量,别名的导入导出是为了不与当前作用域的变量重名。

模块中成员的导出过程

  1. // 在统一导出的时候进行别名化
  2. export { userName as name, hello as hi, User };

脚本中对于模块的导入过程(如果导入的成员在模块中已经进行了别名化处理,那么在使用 import 语句导入的时候,就必须使用别名导入,不然无效)

  1. <script type="module">
  2. // import语句不允许写在后边
  3. // import { userName, hello } from "./module2.js";
  4. // 如果模块中定义了别名,再导入的时候就只能使用别名导入
  5. // import { userName, echo } from "./module2.js";
  6. // import { name, echo } from "./module2.js";
  7. // console.log(name);
  8. // let userName;
  9. // 别名导入
  10. import { name as firstName, echo } from "./module2.js";
  11. // 别名的导入导出是为了不与当前作用域的变量重名
  12. </script>

在对别名的导入过程中,如果当前作用域还是有同名成员时,还可以进行别名处理

模块中默认成员的导入导出

模块中默认成员与普通成员的区别:

  • 单一成员导出区别:
  1. // default可以视为一个变量,default = userName;相当于赋值
  2. // 默认成员
  3. export default userName = "小红";
  4. // 一个模块中只允许一个默认导出
  5. // 一般成员
  6. export function hello(name) {
  7. return "Hello" + name;
  8. }
  • 统一导出的区别
  1. // 将成员导出,将hello视为默认成员导出,其他成员为普通成员
  2. export { userName, hello as default, gender };
  • 模块中默认成员与普通成员的导入的区别
  1. <script type="module">
  2. // 默认模块导入
  3. // 导入默认成员与普通模块的最大区别在于没有大括号
  4. // 导入既有默认成员,又有非默认成员
  5. import hello, { userName, gender } from "./module3.js";
  6. </script>

模块命名空间的作用

命名空间:是一个容器,内部可以包含任何类型的数据,命名空间是一个对象,可以挂载到当前的全局中。

使用一般的导入模块方式和使用命名空间导入模块的方式

一般方式

  1. <script type="module">
  2. // 使用一般方式导入
  3. import { userName, hello, User } from "./module1.js";
  4. </script>

使用命名空间的方式导入

  1. <script type="module">
  2. // 使用命名空间来导入
  3. import * as nameSpace from "./module1.js";
  4. // 可以在当前作用域随便声明变量,不怕与模块中成员同名,因为命名空间是一个对象
  5. let userName;
  6. let hello = () => {};
  7. class User {}
  8. // 查看/使用模块中的成员
  9. console.log(nameSpace);
  10. console.log(nameSpace.userName);
  11. console.log(nameSpace.hello(nameSpace.userName));
  12. console.log(new nameSpace.User("小兰", 18).show());
  13. </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