一个好看的轮播图(js原生)

<template>
  <div class="container">
    <div class="title">

    </div>
    <div id="banner">
      <div class="img-list img-wrapper">
        <div class="img-box">
          <div class="info">
            <h3>one</h3>
          </div>
          <img src="@/assets/projectImage/1.png" alt="" />
        </div>
        <div class="img-box">
          <div class="info">
            <h3>two</h3>
          </div>
          <img src="@/assets/projectImage/2.png" alt="" />
        </div>
        <div class="img-box">
          <div class="info">
            <h3>three</h3>
          </div>
          <img src="@/assets/projectImage/3.png" alt="" />
        </div>
        <div class="img-box">
          <div class="info">
            <h3>four</h3>
          </div>
          <img src="@/assets/projectImage/4.png" alt="" />
        </div>
        <div class="img-box">
          <div class="info">
            <h3>five</h3>
          </div>
          <img src="@/assets/projectImage/5.png" alt="" />
        </div>
        <div class="img-box" id="last-img-box">
          <div class="info">
            <h3>six</h3>
          </div>
          <img src="@/assets/projectImage/6.png" alt="" />
        </div>
      </div>
    </div>
    <div class="btn-group">
      <button class="last btn">
        <svg
          t="1686471404424"
          class="icon left"
          viewBox="0 0 1024 1024"
          version="1.1"
          xmlns="http://www.w3.org/2000/svg"
          p-id="2373"
          width="128"
          height="128"
        >
          <path
            d="M862.485 481.154H234.126l203.3-203.3c12.497-12.497 12.497-32.758 0-45.255s-32.758-12.497-45.255 0L135.397 489.373c-12.497 12.497-12.497 32.758 0 45.254l256.774 256.775c6.249 6.248 14.438 9.372 22.627 9.372s16.379-3.124 22.627-9.372c12.497-12.497 12.497-32.759 0-45.255l-203.3-203.301h628.36c17.036 0 30.846-13.81 30.846-30.846s-13.81-30.846-30.846-30.846z"
            fill=""
            p-id="2374"
          ></path>
        </svg>
      </button>
      <button class="next btn">
        <svg
          t="1686471404424"
          class="icon right"
          viewBox="0 0 1024 1024"
          version="1.1"
          xmlns="http://www.w3.org/2000/svg"
          p-id="2373"
          width="128"
          height="128"
        >
          <path
            d="M862.485 481.154H234.126l203.3-203.3c12.497-12.497 12.497-32.758 0-45.255s-32.758-12.497-45.255 0L135.397 489.373c-12.497 12.497-12.497 32.758 0 45.254l256.774 256.775c6.249 6.248 14.438 9.372 22.627 9.372s16.379-3.124 22.627-9.372c12.497-12.497 12.497-32.759 0-45.255l-203.3-203.301h628.36c17.036 0 30.846-13.81 30.846-30.846s-13.81-30.846-30.846-30.846z"
            fill=""
            p-id="2374"
          ></path>
        </svg>
      </button>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from "vue";
import pic01 from "@/assets/projectImage/1.png";
import pic02 from "@/assets/projectImage/2.png";
import pic03 from "@/assets/projectImage/3.png";
import pic04 from "@/assets/projectImage/4.png";
import pic05 from "@/assets/projectImage/5.png";
import pic06 from "@/assets/projectImage/6.png";

onMounted(() => {
  
  const imgListOne = document.querySelector(".img-list");
  // 获取图片类数组,并将其转化为数组
  let imgBoxList = Array.prototype.slice.call(
    document.querySelectorAll(".img-list .img-box")
  );
  const imgBoxCount = imgBoxList.length;
  const root = document.documentElement;
  const btnGroup = document.querySelector(".btn-group");
  const lastBtn = document.querySelector(".last");
  const nextBtn = document.querySelector(".next");
  const lastImgBox = document.getElementById("last-img-box");

  // 获取--post-spacing和--post-size的值
  const postSpacing = Number(
    getComputedStyle(root).getPropertyValue("--post-spacing").replace("vw", "")
  );
  const postSize = Number(
    getComputedStyle(root).getPropertyValue("--post-size").replace("vw", "")
  );

  // 根据图片的数量动态获取img-list的宽度
  let imgListLength = (postSize + postSpacing) * imgBoxCount;
  console.log(imgListLength);
  // 根据图片的数量动态获取img-box的宽度
  const imgBoxLength = postSize + postSpacing;

  let index = 0;
  let indexOne = 1;
  let timer = null;
  let animationTime = 0.5;

  // 初始化数组中元素的的顺序,将最后一张图片放在第一位与html部分图片展示位置一致
  imgBoxList.unshift(imgBoxList.pop());
  // 设置imgListOne动画时间
  imgListOne.style.transition = animationTime + "s ease";
  // 设置按钮出现时间
  setTimeout(function () {
    btnGroup.style.opacity = "1";
    btnGroup.style.bottom = "5%";
  }, animationTime * 1000);
  // 点击事件
  function cilckFun(flag) {
    //下一张 next
    if (flag == "next") {
      index--;
      console.log(index);
      // 因为右边没有显示的图片比较多,所以可以直接先整体向左移动
      imgListOne.style.left = imgBoxLength * index + "vw";
      setTimeout(function () {
        imgListOne.style.transition = "none";
        // 当点击下一个累计达到图片数量时,相当于要回到原点,则重置变量和位置
        if (Math.abs(index) == imgBoxCount) {
          index = 0;
          imgListOne.style.left = 0;
          imgBoxList.forEach((item) => {
            if (item.id == "last-img-box") {
              item.style.transform = `translateX(-160.68vw)`;
            } else {
              item.style.transform = "none";
            }
          });
        } else {
          // 当第一张图片为last-img-box时,说明已经跑完了一轮,则将其放在最后的位置,初始状态其为-160.68vw
          if (imgBoxList[0].id == "last-img-box") {
            lastImgBox.style.transition = "none";
            lastImgBox.style.transform = "translateX(0px)";
          } else if (index >= 0) {
            /*  
                                这种情况是为了解决在点击完第last,再点击next时造成的bug问题,其实就是回退,再点击last之前
                                没有加transform属性,点击last以后则添加了transform属性,再次点击next按钮后应该不加transform
                            */
            imgBoxList[0].style.transform = "none";
          } else {
            // 正常情况下,点击next,则将最左侧的图片移到最后
            imgBoxList[0].style.transform = "translateX(160.68vw)";
          }
        }
        // 模拟移动情况,将最左侧的图片(元素)移动到最后
        imgBoxList.push(imgBoxList.shift());
      }, animationTime * 1000);
    } else {
      // 上一张 last
      index++;
      console.log(index);
      // 模拟移动情况,把最右侧的图片(元素)移动到最前
      imgBoxList.unshift(imgBoxList.pop());
      // 因为左侧图片只会有一张,所以需要先移动图片到左侧,再进行imgListOne的移到
      if (imgBoxList[0].id == "last-img-box" && index != 0) {
        // 当第一张图片为last-img-box时,说明已经跑完了一轮,此时相对于一开始的位置为-321.36vw
        imgBoxList[0].style.transform = "translateX(-321.36vw)";
      } else if (index < 0) {
        // 这种情况与点击next按钮出现的回退现象一致
        imgBoxList[0].style.transform = "none";
      } else {
        // 正常情况下,点击last,则将最右侧的图片移到最前
        imgBoxList[0].style.transform = "translateX(-160.68vw)";
      }
      imgListOne.style.left = imgBoxLength * index + "vw";
      lastImgBox.style.transition = "none";
      // 当点击下一个累计达到图片数量时,相当于要回到原点,则重置变量和位置
      if (Math.abs(index) == imgBoxCount) {
        index = 0;
        setTimeout(function () {
          imgListOne.style.transition = "none";
          imgListOne.style.left = 0;
          imgBoxList.forEach((item) => {
            if (item.id == "last-img-box") {
              item.style.transform = "translateX(-160.68vw)";
            } else {
              item.style.transform = "none";
            }
          });
        }, animationTime * 1000);
      }
    }
    imgListOne.style.transition = animationTime + "s ease";
  }

  //节流函数
  function throttle(fn, delay) {
    return function () {
      if (timer) {
        return;
      }
      fn.apply(this, arguments);
      timer = setTimeout(() => {
        timer = null;
      }, delay);
    };
  }

  nextBtn.onclick = throttle(() => cilckFun("next"), animationTime * 1000);

  lastBtn.onclick = throttle(() => cilckFun("last"), animationTime * 1000);
});
</script>

<style lang="scss" scoped>
.container {
  width: 100%;
  height: 90vh;
  position: relative;
  // padding: 100px 0;
  // overflow: hidden;
  // background-color: green;
}
@font-face {
  font-family: Millik;
  font-weight: 700;
  src: url(./asset/font/Millik.c3f91cb.ttf) format("truetype");
  text-rendering: optimizeLegibility;
}

:global(:root) {
  --post-spacing: 1.78vw;
  --post-size: 25vw;
  --mask-size: 100vw;
}

* {
  padding: 0;
  margin: 0;
  font-family: Millik, Arial, sans-serif;
  font-size: 62.5%;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  box-sizing: border-box;
}
// body {
//   background: #fff;
//   background-image: url(./asset/image/grid.svg);
//   background-repeat: repeat;
//   background-size: 300px 300px;
// }
.title {
  position: absolute;
  height: 600px;
  width: 800px;
  text-align: center;
  left: 50%;
  top: 5%;
  transform: translate(-50%, -5%);
  p {
    font-size: 4rem;
    font-weight: 800;
    white-space: nowrap;
  }
}
#banner {

  overflow: hidden;
  position: relative;
  width: 100vw;
  height: calc(var(--post-size) / 0.72);
  mask: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDQwIiBoZWlnaHQ9IjUwMCIgdmlld0JveD0iMCAwIDE0NDAgNTAwIiBpZD0iaiI+CiAgPHBhdGggZmlsbD0icmdiKDIwMCwyMDAsMjAwKSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMCAwczI3NS4wNCAxMDAgNzIwIDEwMFMxNDQwIDAgMTQ0MCAwdjUwMHMtMjc1LjA0LTEwMC03MjAtMTAwUzAgNTAwIDAgNTAwVjB6Ii8+Cjwvc3ZnPgo=);
  mask-repeat: no-repeat;
  mask-position: center;
  mask-size: var(--mask-size);
  position: absolute;
  top: 10%;
  .img-wrapper {
    display: flex;
    position: absolute;
    width: 100%;
    float: left;
    height: calc(var(--post-size) / 0.72);
    transform: translate(10.60vw, 0);
    animation: admission 1.5s;
    .img-box {
      height: 100%;
      display: inline-block;
      margin-right: var(--post-spacing);
      position: relative;
      cursor: pointer;

      .info {
        position: absolute;
        display: flex;
        flex-direction: column;
        justify-content: center;
        left: 0;
        top: 0;
        height: 100%;
        width: 100%;
        background: hsla(0, 0%, 9%, 0.5);
        text-align: center;
        color: #fff9f1;
        font-size: 4rem;
      }
      img {
        width: var(--post-size);
        height: 100%;
        object-position: center;
        object-fit: cover;
      }
      &:last-child {
        transform: translate(-160.68vw, 0);
      }
    }
  }
}
.btn-group {
  // height: 0vh;
  position: absolute;
  left: 50%;
  bottom:10%;
  // padding-top: 20px;
  // top: 50%;
  transform: translate(-50%, -50%);
  transition: 1s;
  opacity: 0;
  // background-color: pink; 
  width: 10vw;
  display: flex;
  justify-content: space-between;
  .btn {
    width: 60px;
    height: 60px;
    border-radius: 50%;
    border: 1px solid #171717;
    background-color: #fff;
    margin: 10px;
    cursor: pointer;
    transition: 0.4s;
    box-sizing: border-box;
    &:hover {
      transform: scale(1.2);
      background-color: #000;
      .icon {
        fill: #fff;
      }
    }
    .icon {
      width: 30px;
      height: 30px;
    }
    .right {
      transform: rotate(180deg);
    }
  }
}

.img-list {
  left: 0;
}

@keyframes admission {
  0% {
    transform: translate(140vw, 0);
  }
  100% {
    transform: translate(10.60vw, 0);
  }
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值