PHP 学习之路:第十四天—— JS 实现图片懒加载和轮播图

143 阅读1分钟

一、图片懒加载

1.图片懒加载原理

将页面中的img标签src指向一张小图片或者src为空,然后定义data-src(这个属性可以自定义命名,我才用data-src)属性指向真实的图片。src指向一张默认的图片,否则当src为空时也会向服务器发送一次请求。可以指向loading的地址。

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>懒加载原理</title>
  </head>
  <body>
    <img src="images1/default.png" data-src="./images1/5.jpg" alt="" width="660" />
    <script>
      // 1.文档坐标: html文档,一旦渲染完成,它的大小是固定的

      // 2.视口坐标: 用户看到的文档部分,窗口显示的文档部分

      // 文档与视口之间的关系:
      // 1. 文档 小于或等于 视口
      // 一屏就可以将整个文档显示完成,没有滚动条,例如 baidu

      // 2. 文档 大于 视口
      // 这是常态, 一屏就显示不完,会出现滚动条,通过拖动滚动条查看更多内容
      // 例如 php.cn

      // 视口高度
      let viewHeight = document.documentElement.clientHeight;
      console.log(viewHeight);

      document.documentElement.style.height = "1000px";

      // 滚动高度
      // 通常只需要关注高度即可,因为宽度是受限的,高度是随内容扩展的
      console.log(document.documentElement.scrollTop);

      // 滚动事件
      window.onscroll = function () {
        const img = document.querySelector("img");
        // img.src = img.dataset.src;
        setTimeout(function () {
          img.src = img.dataset.src;
        }, 2000);
      };
    </script>
  </body>
</html>

2.图片懒加载实现

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>图片懒加载案例</title>
    <style>
      .container {
        width: 500px;
        display: grid;
        gap: 10px;
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      }
      .container img {
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <img src="images2/temp.jpg" alt="" data-src="images2/img-1.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-2.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-3.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-4.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-5.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-6.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-7.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-8.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-9.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-10.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-11.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-12.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-13.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-14.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-15.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-16.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-17.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-18.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-19.jpg" />
      <img src="images2/temp.jpg" alt="" data-src="images2/img-20.jpg" />
    </div>

    <script>
      // 所有图片
      const imgs = document.querySelectorAll(".container img");
      // const imgs = document.images;
      // 视口高度
      const clientHeight = document.documentElement.clientHeight;

      // 监听滚动事件
      // "scroll": 滚动事件, onscroll: 事件属性,不是事件名称
      window.addEventListener("scroll", layzyload);

      // 当页面加载完成后立即显示第一屏
      window.addEventListener("load", layzyload);

      // 懒加载的回调
      function layzyload() {
        // 滚动距离
        let scrollTop = document.documentElement.scrollTop;

        imgs.forEach(img => {
          // 这张图片的顶部距离它的父级的高度,是否小于视口高度与滚动距离之和
          if (img.offsetTop < clientHeight + scrollTop) {
            setTimeout(function () {
              img.src = img.dataset.src;
            }, 500);
          }
        });
      }
    </script>
  </body>
</html>

二、轮播图

html 实现:

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>轮播图</title>
    <link rel="stylesheet" href="banner/banner.css" />
  </head>
  <body>
    <div class="container">
      <!-- 1. 图片组 -->
      <nav class="imgs">
        <a href=""><img src="banner/banner1.jpg" alt="" data-index="1" class="active" /></a>
        <a href=""><img src="banner/banner2.jpg" alt="" data-index="2" /></a>
        <a href=""><img src="banner/banner3.jpg" alt="" data-index="3" /></a>
        <a href=""><img src="banner/banner4.jpg" alt="" data-index="4" /></a>
      </nav>

      <!-- 2. 图片中下部的小按钮 -->
      <nav class="btns">
        <!-- 小按钮数量必须与图片数量一致所以应该动态创建 -->
        <!-- <a href="" data-index="1" class="active"></a>
        <a href="" data-index="2"></a>
        <a href="" data-index="3"></a>
        <a href="" data-index="4"></a> -->
      </nav>

      <!-- 3. 翻页 -->
      <nav class="skip">
        <a href="" class="prev">&lt;</a>
        <a href="" class="next">&gt;</a>
      </nav>
    </div>

    <script>
      //所有图片
      const imgs = document.querySelectorAll(".container >.imgs img");
      //按钮组
      const btnGroup = document.querySelector(".container > .btns");
      //翻页按钮
      const skip = document.querySelector(".container > .skip");

      //创建出一组与图片数量对应的小按钮
      function autoCrateBtns(ele, imgLength) {
        //复用文档片断来简化/优化编程
        const frag = document.createDocumentFragment();
        for (let i = 0; i < imgLength; i++) {
          const a = document.createElement("a");
          a.href = "#";
          a.dataset.index = i + 1;
          if (i === 0) a.classList.add("active");
          frag.append(a);
        }
        ele.append(frag);
      }
      autoCrateBtns(btnGroup, imgs.length);

      // 为刚刚生成的小按钮添加点击事件
      const btns = document.querySelectorAll(".container > .btns > *");

      // 二个公共函数
      // 1. 获取激活的元素
      function getActiveEle(eles) {
        // 将元素集合转为真正的数组
        // console.log([...eles]);
        let activeEles = [...eles].filter(ele => ele.classList.contains("active"));
        // console.log(activeEles.shift());
        return activeEles.shift();
      }

      // getActiveEle(btns);
      // getActiveEle(imgs);

      // 2. 设置激活的元素,根据按钮索引更新正在显示的图片
      // 参数就是当前正在点击的按钮的索引
      function setActiveEle(btnIndex) {
        // console.log(btnIndex);
        // console.log(imgs, btns);

        // 1.先将之前的激活的样式去掉
        [imgs, btns].forEach(arr => {
          getActiveEle(arr).classList.remove("active");
          // 2.再根据当前的的自定义索引来重新设置应该激活的按钮和图片
          arr.forEach(item => {
            if (item.dataset.index === btnIndex) {
              item.classList.add("active");
            }
          });
        });
      }

      // 为按钮添加事件
      btns.forEach(btn => btn.addEventListener("click", ev => setActiveEle(ev.target.dataset.index)));

      // 思考:
      // 1. 为翻页按钮添加点击事件,注意最后一张和第一张图片的边界处理
      // 2. 实现轮播图的定时播放
      // 鼠标移入时关闭自动播放,移出时启动自动播放
      // setInterval(),间歇式定时器(重复执行)
      // dispathEvent(): 事件派发器
    </script>
  </body>
</html>

banner.css 文件:

/* 初始化 */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
a {
  text-decoration: none;
}

/* 轮播图的容器 */
.container {
  width: 62.5em;
  height: 22em;
  margin: 1em auto;
  /* 转为定位元素/定位父级 */
  position: relative;
}
/* 图片组 */
.container > .imgs img {
  width: 100%;
  height: 100%;

  /* 默认全部隐藏 */
  display: none;

  /* 将所有的图片进行绝对定位,确保每一次只看到一张,所有图片共享这个容器 */
  position: absolute;
  left: 0;
  top: 0;
}

/* 设置默认显示的图片(第一张) */
.container > .imgs img.active {
  display: block;
}

/* 按钮组(独立按钮) */
.container > .btns {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /* 水平居中 */
  text-align: center;
}
.container > .btns a {
  /* 转成行内块元素: 即能水平排列,双支持宽度设置 */
  display: inline-block;
  padding: 0.5em;
  margin: 0 0.2em;
  background-color: #fff;
  border-radius: 50%;
}
.container > .btns a.active {
  background-color: #000;
}
/* 翻页按钮 */
.container .skip a {
  position: absolute;
  width: 2.5rem;
  height: 5rem;
  line-height: 5rem;
  text-align: center;
  opacity: 0.3;
  top: 9rem;
  font-weight: lighter;

  font-size: 2rem;
  background-color: #ccc;
}
.container .skip .prev {
  left: 0;
}
.container .skip .next {
  right: 0;
}
.container .skip *:hover {
  opacity: 0.6;
  color: #666;
}