原生实现循环轮播动画

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>keyframes&停下再滚动&超出不显示动画&加一组件循环</title>
    <style>
      .content {
        display: flex;
        width: 100px;
        height: 100px;
        margin-left: 50px;
        margin-top: 200px;
        border: 5px dotted black;
        border-radius: 25px;
        flex-direction: row;
        overflow: hidden;
      }
      .list {
        display: flex;
        animation: discolor3 5s linear infinite;
        display: flex;
        border-radius: 25px;
        flex-direction: row;
      }
      .item {
        width: 100px;
        height: 100px;
        flex-shrink: 0;
        font-size: 32px;
        line-height: 100px;
        text-align: center;
      }
      .item-1 {
        background: #ff614c;
      }
      .item-2 {
        background: #bfdc36;
      }
      .item-3 {
        background: #6e80e6;
      }
      .item-4 {
        background: #ff614c;
      }
      @keyframes discolor3 {
        0% {
          transform: translateX(0px);
        }

        16.5% {
          transform: translateX(-100px);
        }

        33% {
          transform: translateX(-100px);
        }

        49.5% {
          transform: translateX(-200px);
        }

        66% {
          transform: translateX(-200px);
        }

        82.5% {
          transform: translateX(-300px);
        }

        100% {
          transform: translateX(-300px);
        }
      }
    </style>
  </head>

  <body>
    <div class="content">
      <div class="list">
        <div class="item-1 item">1</div>
        <div class="item-2 item">2</div>
        <div class="item-3 item">3</div>
        <div class="item-4 item">1</div>
      </div>
    </div>
  </body>
</html>

<html>
  <head>
    <meta charset="utf-8" />
    <title>动态CSS轮播动画</title>
  </head>

  <body>
    <div
      style="
        display: flex;
        align-items: center;
        height: 50px;
        font-size: 30px;
        padding-top: 100px;
        padding-left: 100px;
      "
    >
      <input
        type="checkbox"
        id="overflow-hidden"
        checked="true"
        onchange="refresh()"
      />
      超出隐藏
      <button id="plusButton" onclick="plus()">展位+1</button>
    </div>

    <div id="demoDisplay">
      <div id="demoContainer"></div>
    </div>
    <script>
      // 展位背景色数组,通过取模循环获取
      const palette = ["#863D91", "#F29900", "#F2DE5C", "#F7E9D0", "#B893B6"];
      // 轮播动画名称
      const ANIM_NAME = "carousel-anim";
      // 公共动画参数,确保滚动同步
      const scrollTime = 0.5;
      // 展位停留展示时间
      const displayTime = 2;
      // 展位高或宽
      const step = 150;
      // 展位垂直或水平间隔
      const blankStep = 30;

      // 展位个数计数
      let count = 0;
      plus();

      function plus() {
        count++;
        document.getElementById(
          "plusButton"
        ).textContent = `展位数(${count}) ➕1`;
        appendItem2Container();
        refresh();
      }

      // 追加展位节点到展位容器,为了实现循环滚动,在展位数为2时尾部追加新展位1,展位数大于2时在尾部(追加的新展位1)前插入节点
      function appendItem2Container() {
        const demoContainer = document.getElementById("demoContainer");
        const newItem = createItemElement();
        if (count === 1) {
          demoContainer.appendChild(newItem);
        } else if (count === 2) {
          demoContainer.appendChild(newItem);
          // 新增展位1放在尾部
          const newItem2 = createItemElement();
          demoContainer.appendChild(newItem2);
        } else {
          // 在尾部(追加的新展位1)前插入节点
          demoContainer.insertBefore(newItem, demoContainer.lastChild);
        }
      }

      function refresh() {
        const isOverflowHidden = true;
        let cssInfo = null;
        // 只有展位个数大于1个才需要轮播
        if (count > 1) {
          // 构造动画样式,并且返回CSS字符和动画时间间隔
          cssInfo = buildKeyFramesAndReturnCSSInfo(
            count,
            step,
            blankStep,
            scrollTime,
            displayTime
          );
          if (cssInfo) {
            // 将生成的CSS字符追加到DOM树
            appendAnimStyle2DOM(cssInfo.cssStr);
          }
        }

        // 设置展位显示区域样式,固定大小为一个展位,并设置超出是否隐藏
        document.getElementById(
          "demoDisplay"
        ).style = `display: flex; width: 160px; height: 160px; margin-left: 50px; 
            margin-top: 200px; padding: 10px; border: 5px dotted black; border-radius: 25px; 
            flex-direction: row;overflow: hidden`;

        // 遍历设置展位样式
        const itemTitleElementList =
          demoContainer.getElementsByClassName("item");
        for (let index = 0; index < itemTitleElementList.length; index++) {
          const element = itemTitleElementList[index];
          element.style = `width: 150px; height: 150px; background-color: ${getPaletteColor(
            index % count
          )};text-align: center; line-height: 150px; font-size: 35px; border-radius: 25px; margin-bottom: 30px;
                margin-right: 30px; flex-shrink: 0;}`;
          element.textContent = (index % count) + 1 + "/" + count;
        }

        // 设置展位容器样式,并添加轮播动画属性
        document.getElementById(
          "demoContainer"
        ).style = `display: flex; border-radius: 25px; padding: 5px; 
            flex-direction: "row"; ${ cssInfo
                ? `animation:${ANIM_NAME} ${cssInfo.animDuration}s linear infinite;`
                : ""
            }`;
      }

      // 获取内置展位背景色
      function getPaletteColor(index) {
        return palette[index % palette.length];
      }

      // 创建展位element节点
      function createItemElement() {
        const itemDiv = document.createElement("div");
        itemDiv.className = "item";
        return itemDiv;
      }

      // 构建帧动画style信息,返回CSS信息,含动画时长和样式字符串
      function buildKeyFramesAndReturnCSSInfo(
        count,
        step,
        blankStep,
        scrollTime,
        displayTime
      ) {
        const translate = "translateX";
        // 总时间
        const totalTime = displayTime * count + scrollTime * count;

        // 累计百分比
        let sumPercentage = 0;
        // 累计偏移
        let sumOffset = 0;

        let cssStr = `@keyframes ${ANIM_NAME}{0%{transform:${translate}(0px);}`;
        for (let index = 0; index < count; index++) {
          // 静止展示动画区段
          sumPercentage += displayTime / totalTime;
          console.log(sumPercentage,'sumPercentage')
          cssStr += `${(sumPercentage * 100).toFixed(
            0
          )}%{transform:${translate}(-${sumOffset.toFixed(2)}px);}`;
          // 滚动动画区段
          sumPercentage += scrollTime / totalTime;
          sumOffset += step + blankStep;
          cssStr += `${(sumPercentage * 100).toFixed(
            0
          )}%{transform:${translate}(-${sumOffset.toFixed(2)}px);}`;
        }
        cssStr += "}";

        console.log(cssStr, "cssStr");

        return {
          animDuration: totalTime,
          cssStr,
        };
      }

      // CSS字符串生成style标签追加到DOM树
      function appendAnimStyle2DOM(cssStr) {
        // 将CSS样式信息写入dom head节点
        const head = document.head || document.getElementsByTagName("head")[0];
        const style = document.createElement("style");
        head.appendChild(style);
        // style.type = "text/css";
        if (style.styleSheet) {
          style.styleSheet.cssText = cssStr;
        } else {
          style.appendChild(document.createTextNode(cssStr));
        }
 
      }
    </script>
  </body>
</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值