自己纯原生实现无限滚动

240 阅读3分钟

前言

在项目中特别是数据大屏,会有把某一部分数据进行滚动的需求,之前也在网上找过很多的方法、插件、组件等,实现功能肯定是可以实现,不过呢,想着无限滚动的场景还是挺多的,于是想自己动手写一个出来,毕竟只有自己写过一遍才会收获更多知识点,废话不多说,先看效果

VeryCapture_20240529164344.gif

下面直接贴出html文件

如果是vue组件还可以使用npm包直接下载哦,支持垂直+水平方向滚动

请直接滚动到文章底部

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>无限滚动</title>

</head>
<style>
  body,
  html {
    width: 100vw;
    height: 100vh;
    margin: 0;
    padding: 0;
    list-style: none;
    box-sizing: border-box;
    overflow: hidden;
  }

  .scroll-box {
    width: 500px;
    height: 400px;
    overflow: hidden;
    scrollbar-width: none;
    margin: 100px auto;
    border: 1px solid #000;
    padding: 10px;
    box-sizing: border-box;
    scrollbar-width: none;
    /* firefox */
    -ms-overflow-style: none;
    /* IE 10+ */
  }

  /* 谷歌和safari */
  .scroll-box::-webkit-scrollbar {
    display: none;
  }

  .scroll-content {
    width: 100%;
    height: max-content;
  }

  ul {
    padding: 0;
    margin: 0;
    list-style: none;
    cursor: pointer;

  }

  ul>li {
    color: #333;
    min-height: 2rem;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
  }
</style>

<body>
  <div class="scroll-box">
    <div class="scroll-content">
    <!-- 这里建议把需要做滚动的内容用一个容器包起来 -->
      <ul>
        <li>Lorem ipsum dolor sit amet consectetur.</li>
        <li>Saepe obcaecati ab excepturi qui voluptate.</li>
        <li>Optio dicta consequatur vero vel quis.</li>
        <li>Tenetur eum labore libero excepturi ab.</li>
        <li>Totam ea quaerat id consequatur animi!</li>
        <li>Esse praesentium fuga officiis vero iste.</li>
        <li>Necessitatibus quia quidem itaque commodi consectetur?</li>
        <li>A dicta odit cumque saepe aliquid.</li>
        <li>Ad, aspernatur quod! Reprehenderit, corporis labore!</li>
        <li>Commodi voluptatum reprehenderit ipsa eligendi! Aspernatur.</li>
        <li>Iure tenetur sapiente labore esse distinctio.</li>
        <li>Illo ducimus error explicabo quibusdam ratione?</li>
        <li>Lorem ipsum dolor sit amet consectetur adipisicing.</li>
        <li>Ab beatae tenetur autem? Aspernatur, dolorem natus?</li>
        <li>Sapiente repellendus quisquam nostrum architecto aliquam velit.</li>
        <li>Eveniet possimus quas molestias velit culpa dolorem!</li>
        <li>Eligendi quidem, expedita ea debitis rem libero.</li>
        <li>Provident, sunt. Dolores eum amet voluptatibus consequuntur!</li>
        <li>Vel enim odit magnam consectetur voluptas ratione.</li>
        <li>Error, excepturi iste illo eligendi quae possimus?</li>
        <li>Aperiam dolore labore voluptatibus, a fugiat cupiditate!</li>
        <li>Repellendus autem, veritatis exercitationem accusantium doloribus tempore!</li>
        <li>Exercitationem, ullam voluptatem recusandae asperiores perspiciatis aliquam.</li>
        <li>Error delectus voluptatum aut eligendi explicabo repudiandae?</li>
      </ul>
    </div>
  </div>
</body>

<script>
  let scrollBox = null;
  let content = null;
  let isScroll = false; // 是否开启滚动
  let scrollTop = 0; // 滚动的高度
  let fatherBoxHeight = 0; // 父元素的高度
  let scrollBoxHeight = 0; // 滚动元素的高度
  let isCopy = false; // 是否复制

  window.onload = function () {
    scrollBox = document.querySelector('.scroll-box');
    content = document.querySelector('.scroll-content');
    judgeScroll();

    // 监听父容器的鼠标移入事件
    scrollBox.addEventListener('mouseover', () => {
      stopScroll(false);
    });

    // 监听父容器的鼠标移出事件
    scrollBox.addEventListener('mouseout', () => {
      isScroll = true;
      startScroll();
    })
  }

  // 判断内容是否满足滚动条件,如果满足条件则开启滚动
  const judgeScroll = () => {
    fatherBoxHeight = scrollBox.clientHeight;
    scrollBoxHeight = content.clientHeight;
    if (scrollBoxHeight > fatherBoxHeight) {
      isScroll = true;
    } else {
      isScroll = false;
    }
    scroll();
  };

  // 滚动函数
  const scroll = () => {
    if (isScroll) {
      startScroll();
    } else {
      stopScroll();
    }
  };

  // 开启滚动
  const startScroll = () => {
    requestAnimationFrame(srcollCallback);
    return;
  };

  // 滚动的回调函数
  const srcollCallback = () => {
    if (!isScroll) return;
    scrollTop += 0.5;
    if (scrollTop >= scrollBoxHeight - fatherBoxHeight) {
      if (!isCopy) {
        content.appendChild(content.firstElementChild.cloneNode(true));
        isCopy = true;
      } else {
        // 滚动距离大于等于了滚动区域最大的高度时
        if (scrollTop >= scrollBoxHeight) {
          scrollTop = 0;
          isCopy = false;
          content.removeChild(content.lastElementChild);
        }
      }
    }
    scrollToRun();
    // 再一次调用
    requestAnimationFrame(srcollCallback);
  }

  // 让滚动区域进行滚动
  const scrollToRun = () => {
    if (!isScroll) return;
    content.style.transform = `translateY(-${scrollTop}px)`;
  }

  // 停止滚动
  const stopScroll = (isReset = true) => {
    isScroll = false;

    if (isReset) {
      scrollTop = 0;
    }
  };
</script>

</html>

其中主要思想就是按照匀速把需要滚动的区域做移动,使用的是css transfrom: translateY() 属性,然后在滚动到DOM的底部时,在父元素中把现有的子元素复制一份并添加到父元素中(滚动元素建议使用一个容积(div标签)包起来,方便复制),然后滚动距离大于等于滚动元素自身的高度时,说明第一轮的滚动已经结束,那么把刚刚复制出来的元素从父元素中移除。这样就不会出现滚动时有空白区域的情况,类似于自动轮播图吧。

不想看代码的没关系,直接复制就可以用

如果是在vue项目中使用,唉(手动狗头),不要慌我也很懒,于是又针对vue写了一个组件,直接

npm install w-scroll -S

开箱即用

详细操作请移步:

gitee.com/wen745268/w…

注意

目前只有Vue3+TypeScript版本,其他的大差不差了,有兴趣的朋友可以直接看看源码,勿喷