• 绕圆旋转动画组件,拿过来直接用


    效果图

    简单效果图:
    在这里插入图片描述

    开发效果图:
    在这里插入图片描述

    逻辑:

    通过定时改变一个状态变量,使得每个Item的类名发生改变,然后剩下的就是写css动画了。

    用到的依赖库:

    classNames:灵活控制类名的一个库

    代码

    TSX:

    /*
     * @Author: atwLee
     * @Date: 2022-06-14 11:03:41
     * @LastEditors: atwLee
     * @LastEditTime: 2022-06-14 16:15:36
     * @FilePath: \big-screen-lib\packages\big-screen\src\aroundCircleLoop\index.tsx
     * @Description: 绕圈轮播组件
     */
    
    /**
     * @param
     * AroundCircleWrapper:
     * 1、interval:轮播时间间隔
     * 2、blockW:item宽
     * 3、blockH:item高
     * 4、dataLength:数据集长度
     * 5、openLoop:是否轮播
     * 6、position:切换成相对定位,切换为相对定位后要设置外层宽高(默认为绝对定位,宽高100%)
     *  6.1、wrapperWidth:外层宽
     *  6.2、wrapperHeight:外层高
     *  6.3、show:是否是相对定位
     *
     * AroundCircleItem:
     * num:当前数据项的下标(默认填写index即可)
     * @returns
     *
     * @note
     * 1、数据最少为8个
     * 2、AroundCircleWrapper默认绝对定位,相对定位需手动开启
     */
    import React, { useEffect, useRef, useState, useContext, useMemo } from "react";
    import styles from "./index.less";
    import classNames from "classnames";
    
    const LoopParamContext = React.createContext({});
    export const AroundCircleWrapper: React.FC<{
      /**
       * @description 轮播时间间隔。必填
       */
      interval: number;
      /**
       * @description item宽。必填
       */
      blockW: string;
      /**
       * @description item高。必填
       */
      blockH: string;
      /**
       * @description 数据集长度,填写--数据.length--即可。必填。最少为8个
       */
      dataLength: number;
      /**
       * @description 是否开启轮播,必填
       */
      openLoop: boolean;
      /**
       * @description show:false 为绝对定位,宽高默认100%。
       * true为相对定位,相对定位需定义宽高(wrapperWidth,wrapperHeight)
       */
      position: {
        show: boolean;
        wrapperWidth: string;
        wrapperHeight: string;
      };
    }> = (props: any) => {
      const { interval, blockW, blockH, dataLength, openLoop, position } = props;
      let [animateNum, setAnimateNum] = useState(0);
      let timer = useRef<any>();
      useEffect(() => {
        openLoop && startLoop(); // 开启数据块轮播
        return () => {
          clearInterval(timer.current);
          setAnimateNum(0);
        };
      }, []);
    
      function startLoop() {
        timer.current = setInterval(() => {
          setAnimateNum(animateNum++);
        }, interval);
      }
      const contextValue = useMemo(
        () => ({ animateNum, blockW, blockH, dataLength }),
        [animateNum]
      );
      return (
        <LoopParamContext.Provider value={contextValue}>
          <div
            className={styles.dimensionLayer}
            style={
              position.show
                ? {
                    position: "relative",
                    width: `${position.wrapperWidth}px`,
                    height: `${position.wrapperHeight}px`,
                  }
                : {}
            }
          >
            <div className={styles.dimensionWrapper}>{props.children}</div>
          </div>
        </LoopParamContext.Provider>
      );
    };
    
    export const AroundCircleItem: React.FC<{
      /**
       * @description 控制item轮播的索引,传数组下标即可
       */
      num: number;
    }> = (props: any) => {
      const { num } = props;
      const { animateNum, blockW, blockH, dataLength }: any =
        useContext(LoopParamContext);
      // 判断不在屏幕显示的其他的item
      function isDimensionOther(
        animateNum: number,
        index: number,
        dataLength: number
      ): boolean {
        if (
          (animateNum + index) % dataLength !== 0 &&
          (animateNum + index) % dataLength !== 1 &&
          (animateNum + index) % dataLength !== 2 &&
          (animateNum + index) % dataLength !== 3 &&
          (animateNum + index) % dataLength !== 4 &&
          (animateNum + index) % dataLength !== dataLength - 1 &&
          (animateNum + index) % dataLength !== dataLength - 2 &&
          (animateNum + index) % dataLength !== dataLength - 3
        )
          return true;
        else return false;
      }
      return (
        <div
          className={classNames(
            styles["dimensionItem"],
            { [styles[`dimensionItem0`]]: (animateNum + num) % dataLength === 0 },
            { [styles[`dimensionItem1`]]: (animateNum + num) % dataLength === 1 },
            { [styles[`dimensionItem2`]]: (animateNum + num) % dataLength === 2 },
            { [styles[`dimensionItem3`]]: (animateNum + num) % dataLength === 3 },
            { [styles[`dimensionItem4`]]: (animateNum + num) % dataLength === 4 },
            {
              [styles[`dimensionItemL1`]]:
                (animateNum + num) % dataLength === dataLength - 1,
            },
            {
              [styles[`dimensionItemL2`]]:
                (animateNum + num) % dataLength === dataLength - 2,
            },
            {
              [styles[`dimensionItemL3`]]:
                (animateNum + num) % dataLength === dataLength - 3,
            },
            {
              [styles[`dimensionItemOther`]]: isDimensionOther(
                animateNum,
                num,
                dataLength
              ),
            }
          )}
          style={{
            width: `${blockW}px`,
            height: `${blockH}px`,
            left: `calc(50% - ${blockW / 2}px)`,
          }}
        >
          {props.children}
        </div>
      );
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173

    Less:

    // 0
    @dimensionItem0Transform: translate(0, 0) scale(1);
    // 1&l1
    @dimensionItem1-l1scale: scale(0.88);
    @dimensionItem1TranslateXY: translate(110%, -16%);
    @dimensionItemL1TranslateXY: translate(-110%, -16%);
    // 2&l2
    @dimensionItem2-l2scale: scale(0.76);
    @dimensionItem2TranslateXY: translate(140%, -110%);
    @dimensionItemL2TranslateXY: translate(-140%, -110%);
    // 3&l3
    @dimensionItem3-l3scale: scale(0.64);
    @dimensionItem3TranslateXY: translate(110%, -190%);
    @dimensionItemL3TranslateXY: translate(-110%, -190%);
    // 4&l4
    @dimensionItem4TranslateXY: translate(80%, -230%) scale(0);
    @dimensionItemL4TranslateXY: translate(-80%, -230%) scale(0);
    
    .dimensionLayer {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      left: 0;
      .dimensionWrapper {
        position: relative;
        width: 100%;
        height: 100%;
        contain: strict;
        .dimensionItem {
          position: absolute;
          bottom: 0;
          font-size: 62px;
          background-size: 100% 100%;
          background-repeat: no-repeat;
          cursor: default;
        }
        .dimensionItem0 {
          animation: myAnimation15-0 2s linear forwards;
          @keyframes myAnimation15-0 {
            from {
              transform: @dimensionItemL1TranslateXY @dimensionItem1-l1scale;
            }
            to {
              transform: @dimensionItem0Transform;
            }
          }
        }
        .dimensionItem1 {
          animation: myAnimation0-1 2s linear forwards;
          @keyframes myAnimation0-1 {
            from {
              transform: @dimensionItem0Transform;
            }
            to {
              transform: @dimensionItem1TranslateXY @dimensionItem1-l1scale;
            }
          }
        }
        .dimensionItemL1 {
          animation: myAnimation14-15 2s linear forwards;
          @keyframes myAnimation14-15 {
            from {
              transform: @dimensionItemL2TranslateXY @dimensionItem2-l2scale;
            }
            to {
              transform: @dimensionItemL1TranslateXY @dimensionItem1-l1scale;
            }
          }
        }
        .dimensionItem2 {
          animation: myAnimation1-2 2s linear forwards;
          @keyframes myAnimation1-2 {
            from {
              transform: @dimensionItem1TranslateXY @dimensionItem1-l1scale;
            }
            to {
              transform: @dimensionItem2TranslateXY @dimensionItem2-l2scale;
            }
          }
        }
        .dimensionItemL2 {
          animation: myAnimation13-14 2s linear forwards;
          @keyframes myAnimation13-14 {
            from {
              transform: @dimensionItemL3TranslateXY @dimensionItem3-l3scale;
            }
            to {
              transform: @dimensionItemL2TranslateXY @dimensionItem2-l2scale;
            }
          }
        }
        .dimensionItem3 {
          animation: myAnimation2-3 2s linear forwards;
          @keyframes myAnimation2-3 {
            from {
              transform: @dimensionItem2TranslateXY @dimensionItem2-l2scale;
            }
            to {
              transform: @dimensionItem3TranslateXY @dimensionItem3-l3scale;
            }
          }
        }
        .dimensionItemL3 {
          animation: myAnimation12-13 2s linear forwards;
          @keyframes myAnimation12-13 {
            from {
              transform: @dimensionItemL4TranslateXY;
              opacity: 0;
            }
            to {
              transform: @dimensionItemL3TranslateXY @dimensionItem3-l3scale;
              opacity: 1;
            }
          }
        }
        .dimensionItem4 {
          animation: myAnimation3-4 2s linear forwards;
          @keyframes myAnimation3-4 {
            from {
              transform: @dimensionItem3TranslateXY @dimensionItem3-l3scale;
              opacity: 1;
            }
            to {
              transform: @dimensionItem4TranslateXY;
              opacity: 0;
            }
          }
        }
        .dimensionItemOther {
          opacity: 0;
        }
      }
    }
    
    //example
    .name {
      padding-top: 3%;
      text-align: center;
      color: white;
      font-size: 0.9em;
      width: fit-content;
      margin: auto;
      display: flex;
      align-items: center;
      .arrowLeft {
        width: 80px;
        transform: rotate(180deg);
        margin-right: 26px;
      }
      .arrowRight {
        width: 80px;
        margin-left: 26px;
      }
    }
    .value {
      font-size: 2em;
      text-align: center;
      font-family: DiGiFaceWide;
      color: white;
      font-weight: normal;
      margin-top: 10px;
      span {
        font-size: 0.8em;
      }
    }
    .unit {
      text-align: center;
      color: white;
      // font-weight: bold;
      font-size: 1em;
      margin-top: 2%;
      font-family: PingFang SC-Bold, PingFang SC;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174

    用法

    参数见上文

    // 引入
    import { AroundCircleWrapper, AroundCircleItem } from './components/AroundCircleLoop';
    
    <AroundCircleWrapper
              blockW="750"
              blockH="480"
              dataLength={dataArr.length}
              interval={10000}
              openLoop={true}
              position={{
                show: false,
              }}
            >
              {dataArr.map((item, index) => {
                return (
                  <AroundCircleItem key={index} num={index}>
                    <p>{item.name}</p>
                  </AroundCircleItem>
                );
              })}
            </AroundCircleWrapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    UTF-8 和 Unicode 编码
    Xcode打包ipa文件,查看app包内文件
    Java实现byte数组与Hex互转
    【2023年11月第四版教材】第17章《干系人管理》(合集篇)
    【数据聚类】第四章第二节1:OPTICS算法思想和算法流程
    计算机网络第四章——网络层(上)
    【算法练习Day27】买卖股票的最佳时机 II&&跳跃游戏&&跳跃游戏 II
    uniapp高德地图ios 使用uni.chooseLocation选取位置显示没有搜索到相关数据
    天然橡胶行业洞察:预计2028年将达到306亿美元
    我的创作纪念日
  • 原文地址:https://blog.csdn.net/BWater_monster/article/details/125545069