博客列表 >轮播图示例及购物车示例

轮播图示例及购物车示例

月缺
月缺原创
2021年10月07日 13:19:13935浏览

轮播图示例及购物车示例

轮播图

html部分

  1. <div class="container">
  2. <!-- 1. 图片组 -->
  3. <div class="img-group"></div>
  4. <!-- 2. 图片中下部的小按钮 -->
  5. <div class="btn-group"></div>
  6. <!-- 3. 翻页 -->
  7. <div class="skip">
  8. <a class="prev">&lt;</a>
  9. <a class="next">&gt;</a>
  10. </div>
  11. </div>

css部分

  1. /* 初始化 */
  2. * {
  3. margin: 0;
  4. padding: 0;
  5. box-sizing: border-box;
  6. }
  7. a {
  8. text-decoration: none;
  9. }
  10. /* 轮播图的容器 */
  11. .container {
  12. width: 62.5em;
  13. height: 22em;
  14. margin: 1em auto;
  15. /* 转为定位元素/定位父级 */
  16. position: relative;
  17. }
  18. .container:hover {
  19. cursor: pointer;
  20. }
  21. /* 图片组 */
  22. .container > .img-group img {
  23. width: 100%;
  24. height: 100%;
  25. border-radius: 0.6em;
  26. /* 默认全部隐藏 */
  27. display: none;
  28. /* 将所有的图片进行绝对定位,确保每一次只看到一张,所有图片共享这个容器 */
  29. position: absolute;
  30. left: 0;
  31. top: 0;
  32. }
  33. /* 设置默认显示的图片(第一张) */
  34. .container > .img-group img.active {
  35. display: block;
  36. }
  37. /* 按钮组(独立按钮) */
  38. .container > .btn-group {
  39. position: absolute;
  40. left: 0;
  41. right: 0;
  42. bottom: 1rem;
  43. /* 水平居中 */
  44. text-align: center;
  45. }
  46. .container > .btn-group span {
  47. /* 转成行内块元素: 即能水平排列,双支持宽度设置 */
  48. display: inline-block;
  49. padding: 0.5em;
  50. margin: 0 0.2em;
  51. background-color: #fff;
  52. border-radius: 50%;
  53. }
  54. .container > .btn-group span:hover {
  55. cursor: pointer;
  56. }
  57. .container > .btn-group .active {
  58. background-color: #10d1f3;
  59. }
  60. /* 翻页按钮 */
  61. .container .skip a {
  62. position: absolute;
  63. width: 2.5rem;
  64. height: 2.5rem;
  65. line-height: 2.5rem;
  66. border-radius: 50%;
  67. text-align: center;
  68. opacity: 0.3;
  69. top: 9rem;
  70. font-weight: lighter;
  71. font-size: 2rem;
  72. background-color: #787373;
  73. }
  74. .container .skip .prev {
  75. left: 1rem;
  76. }
  77. .container .skip .next {
  78. right: 1rem;
  79. }
  80. .container .skip *:hover {
  81. opacity: 0.6;
  82. color: #666;
  83. }

js部分

  1. class Swiper {
  2. constructor(imgs, code, imgcode, btncode) {
  3. this.imgs = imgs;
  4. this.code = code;
  5. this.imgcode = imgcode;
  6. this.btncode = btncode;
  7. this.next = null;
  8. this.prev = null;
  9. this.timer = null;
  10. this.clickEvent = new Event("click");
  11. }
  12. init() {
  13. this.next = document.querySelector(".skip .next");
  14. this.prev = document.querySelector(".skip .prev");
  15. this.next.addEventListener('click', ()=>this.nextImg());
  16. this.prev.addEventListener('click', ()=>this.prevImg());
  17. // 1. 生成轮播图所有图片
  18. this.createImgs(this.imgcode, this.imgs.length);
  19. // 2. 生成与轮播图数量对应的小按钮
  20. this.createBtns(this.btncode, this.imgs.length);
  21. this.autoPlay();
  22. // 鼠标移入时停止自动播放,移出时启动自动播放
  23. this.code.addEventListener("mouseover", ()=>this.stopPlay());
  24. this.code.addEventListener("mouseout", ()=>this.autoPlay());
  25. }
  26. // 生成图片
  27. createImgs(parent, length) {
  28. // 正确的做法, 应该是将所有图片,先在内存中创建,然后再统一的插入到页面中, 这样就只需要渲染一次dom一次
  29. // 文档片断元素
  30. const frag = document.createDocumentFragment();
  31. for (let i = 0; i < length; i++) {
  32. const img = document.createElement("img");
  33. img.src = this.imgs[i];
  34. img.alt = `banner${i + 1}`;
  35. // 为每一张图片添加一个自定义属性"data-index", 用它与小按钮进行绑定
  36. img.dataset.index = `${i + 1}`;
  37. if (i === 0) img.classList.add("active");
  38. // 内存中执行了四次
  39. frag.append(img);
  40. }
  41. // 页面中只渲染了一次,效率杠杠的
  42. parent.append(frag);
  43. }
  44. // 生成按钮
  45. createBtns(parent, length) {
  46. const frag = document.createDocumentFragment();
  47. for (let i = 0; i < length; i++) {
  48. const span = document.createElement("span");
  49. span.dataset.index = `${i + 1}`;
  50. if (i === 0) span.classList.add("active");
  51. // 给新生成的按钮,添加点击事件,用来切换图片
  52. span.onclick = ev => this.showImgs(ev);
  53. frag.append(span);
  54. }
  55. parent.append(frag);
  56. }
  57. // 按钮事件
  58. showImgs(ev) {
  59. // 1. 获取所有图片和按钮
  60. const imgArr = this.imgcode.querySelectorAll("img");
  61. const btnArr = this.btncode.querySelectorAll("span");
  62. // 2. 因为我们要根据用户的点击确定当前应该显示哪一个,所以应该将之前的激活全部取消掉
  63. // 但是我们又不知道当前是哪个处于激活状态, 全部过一遍
  64. // btnArr.forEach(item => {
  65. // if (item.classList.contains("active")) item.classList.remove("active");
  66. // });
  67. // imgArr.forEach(item => {
  68. // if (item.classList.contains("active")) item.classList.remove("active");
  69. // });
  70. // 将上面二段代码合并
  71. [btnArr, imgArr].forEach(items => {
  72. items.forEach(item => {
  73. if (item.classList.contains("active")) item.classList.remove("active");
  74. });
  75. // 3. 再给当前正在点击的按钮添加激活,然后再根据当前激活的按钮确定应该显示哪一张图片
  76. ev.target.classList.add("active");
  77. imgArr.forEach(img => {
  78. // 这张应该显示的图片的data-index应该与按钮 的data-index相等,就显示出来
  79. if (ev.target.dataset.index === img.dataset.index) img.classList.add("active");
  80. });
  81. });
  82. }
  83. // 翻页事件
  84. // 向前翻页
  85. prevImg() {
  86. //1. 当前图片和当前的按钮
  87. const currentImg = this.imgcode.querySelector("img.active");
  88. const currentBtn = this.btncode.querySelector("span.active");
  89. // 2. 去掉当前图片和按钮的激活样式
  90. currentImg.classList.remove("active");
  91. currentBtn.classList.remove("active");
  92. // 3. 获取当前图片和按钮的前一个兄弟元素
  93. const prevImg = currentImg.previousElementSibling;
  94. const prevBtn = currentBtn.previousElementSibling;
  95. // 4. 判断,如果存在前一张图片,就设置为激活
  96. if (prevImg !== null && prevBtn !== null) {
  97. prevImg.classList.add("active");
  98. prevBtn.classList.add("active");
  99. } else {
  100. // 将最后一个图片设置为激活显示,实现循环显示
  101. this.imgcode.lastElementChild.classList.add("active");
  102. this.btncode.lastElementChild.classList.add("active");
  103. }
  104. }
  105. // 向后翻页
  106. nextImg() {
  107. //1. 当前图片和当前的按钮
  108. const currentImg = this.imgcode.querySelector("img.active");
  109. const currentBtn = this.btncode.querySelector("span.active");
  110. // 2. 去掉当前图片和按钮的激活样式
  111. currentImg.classList.remove("active");
  112. currentBtn.classList.remove("active");
  113. // 3. 获取当前图片和按钮的前一个兄弟元素
  114. const nextImg = currentImg.nextElementSibling;
  115. const nextBtn = currentBtn.nextElementSibling;
  116. // 4. 判断,如果存在前一张图片,就设置为激活
  117. if (nextImg !== null && nextBtn !== null) {
  118. nextImg.classList.add("active");
  119. nextBtn.classList.add("active");
  120. } else {
  121. // 将最后一个图片设置为激活显示,实现循环显示
  122. this.imgcode.firstElementChild.classList.add("active");
  123. this.btncode.firstElementChild.classList.add("active");
  124. }
  125. }
  126. // 自动播放
  127. autoPlay() {
  128. const self = this;
  129. // ev: 事件对象,在方法总是有效的
  130. this.timer = setInterval(() => {
  131. // console.log(this.next);
  132. this.next.dispatchEvent(this.clickEvent, self.nextImg);
  133. }, 2000);
  134. }
  135. // 自动停止
  136. stopPlay() {
  137. clearInterval(this.timer);
  138. }
  139. }
  140. const imgs = ["images/banner_1.jpg", "images/banner_2.jpg", "images/banner_3.jpg", "images/banner_4.jpg"];
  141. const container = document.querySelector(".container");
  142. // 图片组
  143. const imgGroup = document.querySelector(".container > .img-group");
  144. // 按钮组
  145. const btnGroup = document.querySelector(".container > .btn-group");
  146. // 提供4个参数: 图片数组、轮播图盒子节点元素、图片组盒子节点元素、轮播图底部按钮节点
  147. const swiper = new Swiper(imgs, container, imgGroup, btnGroup);
  148. window.onload = () => swiper.init();

成品效果

轮播图

购物车

html部分

  1. <table>
  2. <caption>
  3. 我的购物车
  4. </caption>
  5. <thead>
  6. <th><input type="checkbox" name="checkAll" id="check-all" checked /><label for="check-all">全选</label></th>
  7. <th>图片</th>
  8. <th>品名</th>
  9. <th>单位</th>
  10. <th>单价/元</th>
  11. <th>数量</th>
  12. <th>金额/元</th>
  13. </thead>
  14. <tbody>
  15. <tr>
  16. <td>
  17. <input type="checkbox" name="item" class="item" value="SN-1020" checked />
  18. </td>
  19. <td>
  20. <a href=""><img src="images/p1.png" alt="" /></a>
  21. </td>
  22. <td>JavaScript权威指南(第七版)</td>
  23. <td></td>
  24. <td class="price">100</td>
  25. <td><input type="number" min="1" value="1" /></td>
  26. <td class="amount">0</td>
  27. </tr>
  28. <tr>
  29. <td>
  30. <input type="checkbox" name="item" class="item" value="SN-1020" checked />
  31. </td>
  32. <td>
  33. <a href=""><img src="images/p2.png" alt="" /></a>
  34. </td>
  35. <td>JavaScript高级程序设计(第四版)</td>
  36. <td></td>
  37. <td class="price">129</td>
  38. <td><input type="number" min="1" value="1" /></td>
  39. <td class="amount">0</td>
  40. </tr>
  41. <tr>
  42. <td>
  43. <input type="checkbox" name="item" class="item" value="SN-1030" checked />
  44. </td>
  45. <td>
  46. <a href=""><img src="images/p3.png" alt="" /></a>
  47. </td>
  48. <td>JavaScript忍者秘籍(第二版)</td>
  49. <td></td>
  50. <td class="price">99</td>
  51. <td><input type="number" min="1" value="1" /></td>
  52. <td class="amount">0</td>
  53. </tr>
  54. <tr>
  55. <td>
  56. <input type="checkbox" name="item" class="item" value="SN-1040" checked />
  57. </td>
  58. <td>
  59. <a href=""><img src="images/p4.png" alt="" /></a>
  60. </td>
  61. <td>ThinkPad X1 Carbon 2021</td>
  62. <td></td>
  63. <td class="price">12999</td>
  64. <td><input type="number" min="1" value="1" /></td>
  65. <td class="amount">0</td>
  66. </tr>
  67. <tr>
  68. <td>
  69. <input type="checkbox" name="item" class="item" value="SN-1050" checked />
  70. </td>
  71. <td>
  72. <a href=""><img src="images/p5.png" alt="" /></a>
  73. </td>
  74. <td>MacBook Pro 16 10代i7 16G 512G</td>
  75. <td></td>
  76. <td class="price">23800</td>
  77. <td><input type="number" min="1" value="1" /></td>
  78. <td class="amount">0</td>
  79. </tr>
  80. </tbody>
  81. <tfoot>
  82. <tr>
  83. <td colspan="5">总计:</td>
  84. <td id="sum">0</td>
  85. <td id="total-amount">0</td>
  86. </tr>
  87. </tfoot>
  88. </table>

css部分

  1. * {
  2. margin: 0;
  3. padding: 0;
  4. box-sizing: border-box;
  5. }
  6. html {
  7. font-size: 10px;
  8. }
  9. box {
  10. font-size: 1.6rem;
  11. }
  12. table {
  13. border-collapse: collapse;
  14. width: 90%;
  15. text-align: center;
  16. margin: 1rem auto;
  17. color: #666;
  18. }
  19. table caption {
  20. margin-bottom: 1rem;
  21. font-size: 2rem;
  22. }
  23. table th,
  24. table td {
  25. padding: 0.5rem;
  26. font-weight: normal;
  27. }
  28. table thead tr:first-of-type {
  29. background-color: rgb(26, 187, 187);
  30. height: 3rem;
  31. color: white;
  32. }
  33. table thead tr:first-of-type:hover {
  34. opacity: 0.8;
  35. cursor: pointer;
  36. }
  37. table input[type="checkbox"] {
  38. width: 1rem;
  39. height: 1rem;
  40. }
  41. /* table tr:nth-of-type(even) {
  42. background-color: #eee;
  43. } */
  44. table tbody tr:hover {
  45. background-color: lightcyan;
  46. transition: 0.5s;
  47. cursor: pointer;
  48. }
  49. table input[type="number"] {
  50. height: 2em;
  51. width: 4em;
  52. border: none;
  53. border-bottom: 1px solid;
  54. outline: none;
  55. text-align: center;
  56. }
  57. /* table input[type="number"]:focus {
  58. background-color: rgb(26, 187, 187);
  59. } */
  60. tbody img {
  61. width: 3em;
  62. transition: all 0.6s;
  63. cursor: pointer;
  64. }
  65. tbody img:hover {
  66. transform: scale(4);
  67. }
  68. tfoot tr {
  69. height: 3rem;
  70. color: coral;
  71. background-color: lightcyan;
  72. }
  73. button {
  74. width: 15rem;
  75. height: 2rem;
  76. outline: none;
  77. border: none;
  78. background-color: rgb(26, 187, 187);
  79. color: white;
  80. letter-spacing: 5px;
  81. }
  82. button:hover {
  83. background-color: coral;
  84. transition: 0.2s;
  85. cursor: pointer;
  86. }
  87. @media screen and (min-width: 400px) {
  88. html {
  89. font-size: 12px;
  90. }
  91. }
  92. @media screen and (min-width: 600px) {
  93. html {
  94. font-size: 14px;
  95. }
  96. }
  97. @media screen and (min-width: 800px) {
  98. html {
  99. font-size: 16px;
  100. }
  101. }

js部分

  1. // 功能一: 完成全选和全不选功能
  2. // 1. 全选复选框
  3. const checkAll = document.querySelector("#check-all");
  4. // 2. 每个商品的复选框
  5. const checkItems = document.getElementsByName("item");
  6. // ==========================================================
  7. // 功能二: 自动计算
  8. // 分析: 所有的计算,都是基于"数量的变化", 第一步就要获取到所有商品数量控件
  9. const numInput = document.querySelectorAll('input[type="number"]');
  10. // 给每一个数量控件绑定一个change事件,进行监听它的变量
  11. // 当控件的值发生变化时, 自动进行重新 计算
  12. numInput.forEach(input => (input.onchange = autoTotal));
  13. // 当页面加载完成时,应该将自动计算函数执行一次(初始化)
  14. window.onload = autoCalculate;
  15. function autoCalculate() {
  16. // 1. 获取每个商品的金额, 金额 = 数量 * 单价
  17. // 数量, 当前有多个商品,所以应该返回一个由数量组成的集合/数组
  18. const numbers = document.querySelectorAll('input[type="number"]');
  19. // console.log(numbers);
  20. // [...numbers].forEach(num => console.log(typeof parseInt(num.value)));
  21. // [...numbers].forEach(num => console.log(num.value * 1));
  22. //map()代替forEach: 因为forEach()没有返回值,map()功能与forEach一样的,但是有一个数组返回值
  23. const numArr = [...numbers].map(num => num.value * 1);
  24. // 获取单价组成的数组
  25. const prices = document.querySelectorAll("tbody .price");
  26. // console.log(prices);
  27. const priceArr = [...prices].map(price => price.textContent * 1);
  28. // console.log(numArr, priceArr);
  29. // 每一个商品与单价的乘积是它的金额,有多个商品,所以应该返回 一个由"金额"组成的数组
  30. // reduce()
  31. const amountArr = [priceArr, numArr].reduce((prev, curr) => prev.map((item, key) => item * curr[key]));
  32. // console.log(amountArr);
  33. // 2. 商品总数
  34. let sum = numArr.reduce((prev, curr) => prev + curr);
  35. // 3. 所有商品总金额
  36. let total = amountArr.reduce((prev, curr) => prev + curr);
  37. // 4. 将以上的计算结果,渲染到页面中
  38. // forEach(function(正在遍历的元素,该元素的索引,数组))
  39. document.querySelectorAll(".amount").forEach((item, index) => (item.textContent = amountArr[index]));
  40. document.querySelector("#sum").textContent = sum;
  41. document.querySelector("#total-amount").textContent = total;
  42. }
  43. // 全选时
  44. checkAll.onchange = (ev) => {
  45. checkItems.forEach(item => (item.checked = ev.target.checked));
  46. if (!ev.target.checked) {
  47. document.querySelector("#sum").textContent = 0;
  48. document.querySelector("#total-amount").textContent = 0;
  49. } else {
  50. autoCalculate()
  51. }
  52. }
  53. // 选择某个商品时, 数量,总金额实时更新
  54. function autoTotal() {
  55. // 1. 获取每个商品的金额, 金额 = 数量 * 单价
  56. // 数量, 当前有多个商品,所以应该返回一个由数量组成的集合/数组
  57. const numbers = document.querySelectorAll('input[type="number"]');
  58. const checkeds = [...checkItems].filter((item, idx) => {
  59. if (item.checked) {
  60. item.dataset.checkidx = idx;
  61. return true;
  62. }
  63. return false;
  64. }).map((item) => item.dataset.checkidx);
  65. const numArr = [...numbers].filter((v, idx) => checkeds.includes(`${idx}`)).map(num => num.value * 1);
  66. console.log([...numbers].filter((v, idx) => checkeds.includes(`${idx}`)));
  67. // 获取单价组成的数组
  68. const prices = document.querySelectorAll("tbody .price");
  69. const priceArr = [...prices].filter((v, idx) => checkeds.includes(`${idx}`)).map(price => price.textContent * 1);
  70. const amountArr = [priceArr, numArr].reduce((prev, curr) => prev.map((item, key) => item * curr[key]));
  71. // 2. 商品总数
  72. let sum = numArr.reduce((prev, curr) => prev + curr);
  73. // 3. 所有商品总金额
  74. let total = amountArr.reduce((prev, curr) => prev + curr);
  75. // 4. 将以上的计算结果,渲染到页面中
  76. document.querySelector("#sum").textContent = sum;
  77. document.querySelector("#total-amount").textContent = total;
  78. }
  79. checkItems.forEach((item)=> item.onchange = ()=>{
  80. // 全选复选框选中状态根据所有商品的复选框状态更改
  81. checkAll.checked = [...checkItems].every(item => item.checked);
  82. autoTotal();
  83. });

成品效果

购物车

```

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