博客列表 >JS原生实现选项卡和图片懒加载

JS原生实现选项卡和图片懒加载

陈强
陈强原创
2021年01月12日 15:53:55549浏览

选项卡

  1. //css样式
  2. <style>
  3. * {
  4. margin: 0;
  5. padding: 0;
  6. box-sizing: border-box;
  7. }
  8. a {
  9. text-decoration: none;
  10. color: #333;
  11. }
  12. ul li {
  13. list-style: none;
  14. }
  15. .con {
  16. width: 20em;
  17. box-shadow: 0 0 3px #ccc;
  18. margin: 2em;
  19. }
  20. .con .tab {
  21. display: grid;
  22. grid-template-columns: repeat(3, 1fr);
  23. text-align: center;
  24. background-color: #ccc;
  25. }
  26. .con .tab li {
  27. padding: 0.5em 0;
  28. cursor: pointer;
  29. }
  30. .con .active {
  31. background-color: #fff;
  32. }
  33. .con .item {
  34. padding: 0.5em;
  35. }
  36. .con .item li {
  37. padding: 0.2em 0;
  38. }
  39. .item {
  40. padding: 20px;
  41. display: none;
  42. }
  43. .item.active {
  44. display: block;
  45. }
  46. </style>
  47. //html代码
  48. <div class="con">
  49. <ul class="tab">
  50. <li class="active" data-index="1">第一个</li>
  51. <li data-index="2">第二个</li>
  52. <li data-index="3">第三个</li>
  53. </ul>
  54. <ul data-index="1" class="item active">
  55. <li><a href="#">第一个选项卡内容</a></li>
  56. <li><a href="#">第一个选项卡内容</a></li>
  57. <li><a href="#">第一个选项卡内容</a></li>
  58. <li><a href="#">第一个选项卡内容</a></li>
  59. <li><a href="#">第一个选项卡内容</a></li>
  60. <li><a href="#">第一个选项卡内容</a></li>
  61. <li><a href="#">第一个选项卡内容</a></li>
  62. <li><a href="#">第一个选项卡内容</a></li>
  63. <li><a href="#">第一个选项卡内容</a></li>
  64. <li><a href="#">第一个选项卡内容</a></li>
  65. </ul>
  66. <ul data-index="2" class="item">
  67. <li><a href="#">第二个选项卡内容</a></li>
  68. <li><a href="#">第二个选项卡内容</a></li>
  69. <li><a href="#">第二个选项卡内容</a></li>
  70. <li><a href="#">第二个选项卡内容</a></li>
  71. <li><a href="#">第二个选项卡内容</a></li>
  72. <li><a href="#">第二个选项卡内容</a></li>
  73. <li><a href="#">第二个选项卡内容</a></li>
  74. <li><a href="#">第二个选项卡内容</a></li>
  75. <li><a href="#">第二个选项卡内容</a></li>
  76. <li><a href="#">第二个选项卡内容</a></li>
  77. </ul>
  78. <ul data-index="3" class="item">
  79. <li><a href="#">第三个选项卡内容</a></li>
  80. <li><a href="#">第三个选项卡内容</a></li>
  81. <li><a href="#">第三个选项卡内容</a></li>
  82. <li><a href="#">第三个选项卡内容</a></li>
  83. <li><a href="#">第三个选项卡内容</a></li>
  84. <li><a href="#">第三个选项卡内容</a></li>
  85. <li><a href="#">第三个选项卡内容</a></li>
  86. <li><a href="#">第三个选项卡内容</a></li>
  87. <li><a href="#">第三个选项卡内容</a></li>
  88. <li><a href="#">第三个选项卡内容</a></li>
  89. </ul>
  90. </div>
  91. //js代码
  92. <script>
  93. const tab = document.querySelector(".con .tab");
  94. const items = document.querySelectorAll(".con .item");
  95. tab.onmouseover = (ev) => {
  96. [...tab.children].forEach((item) => item.classList.remove("active"));
  97. console.log([Array.from(tab.children)]);
  98. ev.target.classList.add("active");
  99. items.forEach((item) => item.classList.remove("active"));
  100. [...items].filter((item) => item.dataset.index === ev.target.dataset.index)[0].classList.add("active");
  101. };
  102. </script>

图片懒加载

  1. //html代码
  2. <ul class="imgs">
  3. <img src="images/temp.jpg" alt="" data-src="images/img-1.jpg" />
  4. <img src="images/temp.jpg" alt="" data-src="images/img-2.jpg" />
  5. <img src="images/temp.jpg" alt="" data-src="images/img-3.jpg" />
  6. <img src="images/temp.jpg" alt="" data-src="images/img-4.jpg" />
  7. <img src="images/temp.jpg" alt="" data-src="images/img-5.jpg" />
  8. <img src="images/temp.jpg" alt="" data-src="images/img-6.jpg" />
  9. <img src="images/temp.jpg" alt="" data-src="images/img-7.jpg" />
  10. <img src="images/temp.jpg" alt="" data-src="images/img-8.jpg" />
  11. <img src="images/temp.jpg" alt="" data-src="images/img-9.jpg" />
  12. <img src="images/temp.jpg" alt="" data-src="images/img-10.jpg" />
  13. <img src="images/temp.jpg" alt="" data-src="images/img-11.jpg" />
  14. <img src="images/temp.jpg" alt="" data-src="images/img-12.jpg" />
  15. <img src="images/temp.jpg" alt="" data-src="images/img-13.jpg" />
  16. <img src="images/temp.jpg" alt="" data-src="images/img-14.jpg" />
  17. <img src="images/temp.jpg" alt="" data-src="images/img-15.jpg" />
  18. <img src="images/temp.jpg" alt="" data-src="images/img-16.jpg" />
  19. <img src="images/temp.jpg" alt="" data-src="images/img-17.jpg" />
  20. </ul>
  21. //js代码
  22. <script>
  23. //获取图片列表
  24. const imgs = document.querySelectorAll(".imgs img");
  25. //获取当前视口高度
  26. const clientHeight = document.documentElement.clientHeight;
  27. window.addEventListener("scroll", layzyload);
  28. window.addEventListener("load", layzyload);
  29. function layzyload() {
  30. //获取滚动高度
  31. let scrollTop = document.documentElement.scrollTop;
  32. //遍历当前图片是否到了可视区 图片到顶部的高度小于视口+滚动高度,即认为图片进入可视区
  33. imgs.forEach((img) => {
  34. if (img.offsetTop < scrollTop + clientHeight) {
  35. setTimeout(() => (img.src = img.dataset.src), 500);
  36. }
  37. });
  38. }
  39. </script>

轮播图

  1. //html代码
  2. <div class="container">
  3. <!-- 1. 图片组 -->
  4. <nav class="imgs">
  5. <a href="#"
  6. ><img src="banner/banner1.jpg" alt="" data-index="1" class="active"
  7. /></a>
  8. <a href="#"><img src="banner/banner2.jpg" alt="" data-index="2" /></a>
  9. <a href="#"><img src="banner/banner3.jpg" alt="" data-index="3" /></a>
  10. <a href="#"><img src="banner/banner4.jpg" alt="" data-index="4" /></a>
  11. </nav>
  12. <!-- 2. 与图片组对应的按钮组(一个个独立的,数量与图片数量是相同的) -->
  13. <nav class="btns">
  14. <!-- 这些小按钮应该是js根据图片数量动态来创建 -->
  15. </nav>
  16. <!-- 3. 翻页按钮(只有二个,分别在左右) -->
  17. <nav class="skip">
  18. <!-- &lt;: 实体符号 -->
  19. <a href="#" class="prev">&lt;</a>
  20. <a href="#" class="next">&gt;</a>
  21. </nav>
  22. </div>
  23. //JS代码
  24. <script>
  25. // 获取相关的元素对象
  26. // 图片组
  27. const imgs = document.querySelectorAll(".container > .imgs img");
  28. // 按钮组
  29. const btnGroup = document.querySelector(" .container > .btns");
  30. // 翻页按钮
  31. const skip = document.querySelector(" .container > .skip");
  32. // 自动生成按钮组,数量与图片数量一致
  33. function autoCreateBtns(ele, imgLength) {
  34. // 使用文档片断
  35. const frag = document.createDocumentFragment();
  36. for (let i = 0; i < imgLength; i++) {
  37. const a = document.createElement("a");
  38. // #: 防止默认行为,更加规范用 ev.preventDefault();
  39. a.href = "#";
  40. // 自定义数据属性
  41. a.dataset.index = i + 1;
  42. // 为第一个按钮添加高亮,这是默认的
  43. if (i === 0) a.classList.add("active");
  44. frag.appendChild(a);
  45. }
  46. ele.appendChild(frag);
  47. }
  48. // 调用该函数自动生成与图片一一对应的小按钮
  49. autoCreateBtns(btnGroup, imgs.length);
  50. // 获取到刚生成的按钮组中所有按钮
  51. const btns = document.querySelectorAll(" .container > .btns > *");
  52. // 下面声明2个公共函数
  53. // 1. 获取激活的元素
  54. function getActiveEle(eles) {
  55. let activities = Array.from(eles).filter(img =>
  56. img.classList.contains("active")
  57. );
  58. return activities.shift();
  59. }
  60. // 2. 设置激活的元素
  61. function setActiveEle(btnIndex) {
  62. // 同时遍历所有图片与按钮
  63. [imgs, btns].forEach(arr => {
  64. // 取消当前激活元素的状态
  65. getActiveEle(arr).classList.remove("active");
  66. // 根据当前用户点击的按钮索引,重置应该激活的元素
  67. arr.forEach(item => {
  68. if (item.dataset.index === btnIndex) {
  69. item.classList.add("active");
  70. }
  71. });
  72. });
  73. }
  74. // 为每一个独立的小按钮添加事件,不要使用事件代理
  75. btns.forEach(btn =>
  76. btn.addEventListener(
  77. "click",
  78. ev => setActiveEle(ev.target.dataset.index),
  79. false
  80. )
  81. );
  82. // 作业1: 为每个翻页按钮添加事件完成图片翻页(兄弟节点的处理)
  83. skip.addEventListener("click", skipImg, false);
  84. // 单独写一个事件监听器,为后面的事件自动派发做准备
  85. skip.children[0].addEventListener("click", skipImg, false);
  86. // 将前后翻页,使用一个回调统一处理
  87. function skipImg(ev) {
  88. // 当前激活的图片,实际上这里用不到它,而应该用它的父级<a>来判断是否存在兄弟节点
  89. let currentImg = getActiveEle(imgs);
  90. // 当前图片组父元素,注意<img>父级是<a>,<a>的父级才是需要的父节点
  91. let parentEle = currentImg.parentElement.parentElement;
  92. // 当前元素的前一个兄弟节点:previousElementSibling;
  93. let prevEle = currentImg.parentElement.previousElementSibling;
  94. // 当前元素的下一个兄弟节点:nextElementSibling;
  95. let nextEle = currentImg.parentElement.nextElementSibling;
  96. // 第一张图片, firstElementChild第一个子元素
  97. let firstImg = parentEle.firstElementChild.firstElementChild;
  98. // 最后一张图片, firstElementChild, 最后一个子元素
  99. let lastImg = parentEle.lastElementChild.firstElementChild;
  100. let activeImg = currentImg;
  101. // 向前翻页
  102. if (ev.target.classList.contains("prev")) {
  103. // 如果存在前一张图片,就使用它,否则就使用最后一张图片来更新它,形成循环显示的效果
  104. let activeImg =
  105. prevEle !== null ? prevEle.firstElementChild : lastImg;
  106. // 使用激活元素来同步更新图片与按钮
  107. setActiveEle(activeImg.dataset.index);
  108. }
  109. // 向后翻页
  110. if (ev.target.classList.contains("next")) {
  111. // 如果不存在下一张图片,就用第一张图片更新它
  112. let activeImg =
  113. nextEle !== null ? nextEle.firstElementChild : firstImg;
  114. setActiveEle(activeImg.dataset.index);
  115. }
  116. }
  117. // 作业2: 图片每隔2秒自动播放(定时器,事件自动派发)
  118. let timer = null;
  119. const slider = document.querySelector(".container");
  120. slider.addEventListener("mouseout", startTimer, false);
  121. slider.addEventListener("mouseover", clearTimer, false);
  122. // 启动定时器
  123. function startTimer() {
  124. // 创建自定义事件对象
  125. const clickEvent = new Event("click");
  126. timer = setInterval(
  127. () => skip.children[0].dispatchEvent(clickEvent),
  128. 2000
  129. );
  130. }
  131. // 清除定时器
  132. function clearTimer() {
  133. clearInterval(timer);
  134. }
  135. </script>
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议