无限循环滚动不定宽横幅

如题。

复制代码
<html lang="zh-CN">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>不定宽无限滚动</title>
  <style>
    * {
      -webkit-box-sizing: border-box;
      box-sizing: border-box;
    }

    body {
      background: darkcyan;
      margin: 0;
    }

    .no-wrap {
      white-space: nowrap !important;
    }

    .container {
      /* max-width: 992px; */
      width: 100vw;
      margin: 0 auto;
      overflow: hidden;
    }

    .grid {
      display: block;
      font-size: 0;
    }

    .cell {
      display: inline-block;
      font-size: 2rem;
      font-weight: 700;
      position: relative;
      width: 100%;
      height: 30vh;
      padding: 1rem .5rem;
      text-align: center;
      cursor: pointer;
    }

    .cell .content {
      display: block;
      position: absolute;
      top: .5rem;
      bottom: .5rem;
      left: .5rem;
      right: .5rem;
      padding: 1rem;
      color: #555;
      background: #fff;
      box-shadow: 0 2px 10px -10px #ccc;
    }

    .cell.w16 {
      width: 16%;
      width: calc(100% / 6)
    }

    .cell.w25 {
      width: 25%
    }

    .cell.w33 {
      width: 33%;
      width: calc(100% / 3)
    }

    .cell.w50 {
      width: 50%
    }

    .cell.w66 {
      width: 66%;
      width: calc(100% / (3 / 2))
    }

    .cell.w75 {
      width: 75%
    }

    .cell.w83 {
      width: 83%;
      width: calc(100% / (6 / 5))
    }

    .cell.w100 {
      width: 100%
    }

    h1,
    h2 {
      text-align: center;
      color: #fff;
    }

    h1 {
      font-size: 3rem;
      margin-bottom: .15rem;
    }

    h2 {
      font-size: 1.3rem;
      margin-top: .15rem;
      margin-bottom: 15vh;
    }
  </style>
</head>

<body>
  <h1>无限滚动横幅</h1>
  <h2>( hover播放/暂停 )</h2>
  <div class="container">
    <div class="grid infinite-banner">
      <div class="cell w66">
        <div class="content">
          开始
        </div>
      </div>
      <div class="cell w33">
        <div class="content">
          1
        </div>
      </div>
      <div class="cell w25">
        <div class="content">
          2
        </div>
      </div>
      <div class="cell w25">
        <div class="content">
          3
        </div>
      </div>
      <div class="cell w50">
        <div class="content">
          4
        </div>
      </div>
      <div class="cell w100">
        <div class="content">
          5
        </div>
      </div>
      <div class="cell w16">
        <div class="content">
          6
        </div>
      </div>
      <div class="cell w83">
        <div class="content">
          7
        </div>
      </div>
      <div class="cell w25">
        <div class="content">
          8
        </div>
      </div>
      <div class="cell w75">
        <div class="content">
          9
        </div>
      </div>
      <div class="cell w66">
        <div class="content">
          10
        </div>
      </div>
      <div class="cell w33">
        <div class="content">
          结束
        </div>
      </div>
    </div>
  </div>
  <script>
    // 动画对象
    let bannerAnimation

    // 获取滚动显示元素和其子元素
    const bannerEl = document.querySelector('.grid.infinite-banner')
    const cells = bannerEl.querySelectorAll('.cell')

    /**
     * 创建无限滚动动画
     * 检查元素是否具有animate方法,如果没有则不执行动画
     * 计算所有子元素的总宽度,并基于这个宽度创建一个无限循环的线性动画
     */
    const createBannerAnimation = () => {
      // 检查bannerEl元素是否存在animate方法
      if ('animate' in bannerEl && typeof bannerEl.animate === 'function') {
        // 如果已有动画,取消之前的动画
        if (bannerAnimation) bannerAnimation.cancel()

        // 避免文本自动换行影响动画效果
        bannerEl.style.whiteSpace = 'nowrap'

        // 初始化位移变量,用于计算动画的最终位移量
        let displacement = 0
        // 遍历所有子元素,累加宽度以计算总位移量
        for (const cell of cells) displacement += cell.clientWidth
        // 调整位移量
        displacement = (displacement - bannerEl.clientWidth) << 0

        // 创建并启动动画,使轮播图从右向左滚动
        bannerAnimation = bannerEl.animate(
          [
            { transform: 'matrix(1, 0, 0, 1, 0, 0)', offset: 0 },
            {
              transform: `matrix(1, 0, 0, 1, ${-displacement}, 0)`,
              offset: 1
            }
          ],
          {
            duration: cells.length * 3000, // 动画总时长
            easing: 'linear', // 匀速动画效果
            delay: 0, // 无延迟启动
            iterations: Infinity, // 无限循环
            direction: 'normal', // 'reverse'
            fill: 'forwards' // 动画结束后保持最终状态
          }
        )
      }
    }

    /**
     * 播放滚动动画
     */
    const playBannerAnimation = () => {
      if (bannerAnimation && bannerAnimation.playState === 'paused')
        bannerAnimation.play()
    }

    /**
     * 暂停滚动动画
     */
    const pauseBannerAnimation = () => {
      if (bannerAnimation && bannerAnimation.playState === 'running')
        bannerAnimation.pause()
    }

    /**
     * 防抖
     */
    const debounce = (func) => {
      let scheduled, context, args;
      return () => {
        context = this; args = Array.from(arguments);
        if (scheduled) window.cancelAnimationFrame(scheduled);
        scheduled = window.requestAnimationFrame(() => {
          func.apply(context, args);
          scheduled = null;
        });
      };
    };

    // 创建动画,添加鼠标事件
    if ('animate' in bannerEl && typeof bannerEl.animate === 'function') {
      createBannerAnimation()
      bannerEl.addEventListener('mouseenter', pauseBannerAnimation, false)
      bannerEl.addEventListener('mouseleave', playBannerAnimation, false)
      window.addEventListener(
        'resize',
        debounce(createBannerAnimation),
        false
      )
    } else {
      // 浏览器不支持 Web Animation API
    }
  </script>
</body>

</html>
相关推荐
文城5211 小时前
HTML-day1(学习自用)
前端·学习·html
阿珊和她的猫1 小时前
Vue 和 React 的生态系统有哪些主要区别
前端·vue.js·react.js
偷光1 小时前
深度剖析 React 的 useReducer Hook:从基础到高级用法
前端·javascript·react.js
The_era_achievs_hero2 小时前
动态表格html
前端·javascript·html
Thomas_YXQ2 小时前
Unity3D Shader 简析:变体与缓存详解
开发语言·前端·缓存·unity3d·shader
2201_756942643 小时前
react入门笔记
javascript·笔记·react.js
傻小胖3 小时前
ES6 Proxy 用法总结以及 Object.defineProperty用法区别
前端·javascript·es6
Web极客码3 小时前
如何跟踪你WordPress网站的SEO变化
前端·搜索引擎·wordpress
横冲直撞de4 小时前
高版本electron使用iohook失败(使用uiohook-napi替代)
前端·javascript·electron
_Eden_4 小时前
认识Electron 开启新的探索世界一
前端·javascript·electron