搜索
您的当前位置:首页正文

焦点图(轮播图)的实现及详解

来源:易榕旅网
<!DOCTYPE html>
<html lang="en">
  <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>Slider</title>
  </head>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    .img-container {
      margin: 20px auto;
      display: flex;
      align-items: center;
      overflow: hidden;
      position: relative;
      justify-content: center;
    }
    img {
      position: absolute;
      transition: all 0.3s ease-in-out;
      height: 100%;
    }
  </style>
  <body>
    <div class="img-container">
      <img
        class="previous"
        src="./img/中岛美雪.png"
        alt=""
        srcset=""
        h="362"
        w="578"
      />
      <img
        h="1200"
        w="1920"
        class="current"
        src="./img/华盛顿北瀑布国家公园.jpg"
        alt=""
        srcset=""
      />
      <img h="640" w="640" class="next" src="./img/星空.jpg" alt="" srcset="" />
    </div>
    <button class="prev">Previous</button>
    <button class="nex">Next</button>
  </body>
  <script>
    /*
    思路:这里设置三个图片,分别是上一张,当前,下一张(previous,current,next),它们均为绝对定位,父容器为相对定位。
    current是当前实际显示的图片,默认left和right都为0,previous默认right为100%,next的left为100%。我们通过
    设置current的left和right来实现图片的切换,当我们选择上一张时,current的left渐变为100%,而previous的left
    渐变为0。next的right直接变为100%。当我们选择下一张是只需反过来即可,此时需要注意当动画结束后需要对于previous
    ,current,next的left和right进行重置(元素的类名先变而后选择器重置),以便下一次动画。 
    */
    const container = document.querySelector('.img-container');
    let previous = document.querySelector('.previous');
    let next = document.querySelector('.next');
    let current = document.querySelector('.current');
    let prevBtn = document.querySelector('.prev');
    let nextBtn = document.querySelector('.nex');
    /*如果current高度大于600则使用600作为容器高度否则则采用图片的高度
      这里为了保证图片不会失真,我们将实际高度比上图片的高度获取实际缩放比,将其与图片原始宽度相乘得到最佳实际宽度
    */
    let height = getHeight(current) > 600 ? 600 : getHeight(current);
    let width = (height / getHeight(current)) * getWidth(current);
    let autoTimer;
    //默认将容器的宽度和高度设置为current的宽度和高度
    container.style.height = `${height}px`;
    container.style.width = `${width}px`;
    //设置默认值
    previous.style.right = `100%`;
    next.style.left = `100%`;
    //创建自动轮播的效果,默认时间时三秒一换,这里使用一个函数将其包含以便调用
    const auto = function () {
      //设置实际的轮播定时器
      autoTimer = setInterval(() => {
        current.style.right = `0%`;
        const timer = setInterval(() => {
          if (getLeftValue(next) <= 0) {
            clearInterval(timer);
            let height = getHeight(next) > 600 ? 600 : getHeight(next);
            let width = (height / getHeight(next)) * getWidth(next);
            container.style.height = `${height}px`;
            container.style.width = `${width}px`;
            previous.classList.remove('previous');
            previous.classList.add('next');
            current.classList.remove('current');
            current.classList.add('previous');
            next.classList.remove('next');
            next.classList.add('current');
            previous = document.querySelector('.previous');
            next = document.querySelector('.next');
            current = document.querySelector('.current');
            previous.removeAttribute('style');
            next.removeAttribute('style');
            previous.style.right = `100%`;
            next.style.left = `100%`;
            return;
          }
          next.style.left = `${getLeftValue(next) - 10}%`;
          current.style.right = `${getRightValue(current) + 10}%`;
        }, 10);
      }, 3000);
    };
    //页面加载后默认直接调用自动轮播函数
    auto();
    prevBtn.addEventListener('click', () => {
      //点击上一张和下一张时清除自动轮播的定时器
      clearInterval(autoTimer);
      //我们必须先设置一个默认值否则会导致显示的异常,因为默认它是没有设置left和right的
      current.style.left = `0%`;
      const timer = setInterval(() => {
        //当current的left等于0时停止动画,这里的动画设置的默认时长为10*10ms
        if (getLeftValue(current) === 100) {
          clearInterval(timer);
          //将容器设置为上一张的宽度和高度,因为这里是上一张,因此此时上一张即为当前实际显示的图片
          let height = getHeight(previous) > 600 ? 600 : getHeight(previous);
          let width = (height / getHeight(previous)) * getWidth(previous);
          container.style.height = `${height}px`;
          container.style.width = `${width}px`;
          //重置类名
          previous.classList.remove('previous');
          previous.classList.add('current');
          current.classList.remove('current');
          current.classList.add('next');
          next.classList.remove('next');
          next.classList.add('previous');
         //重置选择器
          previous = document.querySelector('.previous');
          next = document.querySelector('.next');
          current = document.querySelector('.current');
         //去除冗余的样式
          previous.removeAttribute('style');
          next.removeAttribute('style');
          previous.style.right = `100%`;
          next.style.left = `100%`;
          auto();
          return;
        }
        //动画效果
        previous.style.right = `${getRightValue(previous) - 10}%`;
        current.style.left = `${getLeftValue(current) + 10}%`;
      }, 10);
    });
    nextBtn.addEventListener('click', () => {
      clearInterval(autoTimer);
      current.style.right = `0%`;
      const timer = setInterval(() => {
        if (getLeftValue(next) <= 0) {
          clearInterval(timer);
          let height = getHeight(next) > 600 ? 600 : getHeight(next);
          let width = (height / getHeight(next)) * getWidth(next);
          container.style.height = `${height}px`;
          container.style.width = `${width}px`;
          previous.classList.remove('previous');
          previous.classList.add('next');
          current.classList.remove('current');
          current.classList.add('previous');
          next.classList.remove('next');
          next.classList.add('current');
          previous = document.querySelector('.previous');
          next = document.querySelector('.next');
          current = document.querySelector('.current');
          previous.removeAttribute('style');
          next.removeAttribute('style');
          previous.style.right = `100%`;
          next.style.left = `100%`;
          auto();
          return;
        }
        next.style.left = `${getLeftValue(next) - 10}%`;
        current.style.right = `${getRightValue(current) + 10}%`;
      }, 10);
    });
    //鼠标移入移出时清除和设置自动轮播的定时器
    container.addEventListener('mouseenter', () => {
      clearInterval(autoTimer);
      //鼠标移移出时重启自动轮播,注意为了避免同一次移出造成mouseleave的重复调用,每次调用mouseleave时先清除定时器
      current.addEventListener('mouseleave', () => {
        clearInterval(autoTimer);
        auto();
      });
    });
 
    function getWidth(img) {
      return parseInt(img.getAttribute('w'));
    }
    function getHeight(img) {
      return parseInt(img.getAttribute('h'));
    }
    function getLeftValue(ele) {
      if (ele.style.left === '') return 0;
      return parseInt(ele.style.left.replace('%', ''));
    }
    function getRightValue(ele) {
      if (ele.style.right === '') return 0;
      return parseInt(ele.style.right.replace('%', ''));
    }
  </script>
</html>

因篇幅问题不能全部显示,请点此查看更多更全内容

Top