无限循环滚动不定宽横幅

如题。

复制代码
<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>
相关推荐
xjt_09017 分钟前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农19 分钟前
Vue 2.3
前端·javascript·vue.js
夜郎king43 分钟前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳1 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵2 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星2 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_2 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js
未来龙皇小蓝2 小时前
RBAC前端架构-01:项目初始化
前端·架构
程序员agions2 小时前
2026年,微前端终于“死“了
前端·状态模式
万岳科技系统开发2 小时前
食堂采购系统源码库存扣减算法与并发控制实现详解
java·前端·数据库·算法