使用js和css 实现div旋转围绕圆分布排列

记录,以防忘记

围绕圆

复制代码
import React, { useEffect } from 'react';
import './index.scoped.scss';


const Test = () => {


    const arr = Array.from({ length: 28 }, (_, index) => index + 1);

    useEffect(() => {
        const dayTotal = arr.length;

        // 动态设置每个点的旋转角度
        const dots = document.querySelectorAll('.dot') as NodeListOf<HTMLElement>;
        const pDeg = 360 / dayTotal;
        dots.forEach((dot, index) => {
            dot.style.transform = `rotate(${index * pDeg}deg) translate(0, -200px)`;
        });
    }, [arr.length]);


    return <div className='flex items-center justify-center w-full h-[100vh]'>

        <div className='relative bg-gray-700 rounded-full box'>
            {arr.map((item, index) => {
                return <div key={index} className='absolute bg-blue-400 dot'>{item}</div>;
            })}
        </div>
    </div>;
};

export default Test;



// scss


$containSize: 400px;
$ballSize: 20px;

.box {
    width: $containSize;
    height: $containSize;
    position: relative;

    .dot {
        width: $ballSize;
        height: $ballSize;
        position: absolute;
        top: 50%;
        left: 50%;
        margin-left: calc(-1 * $ballSize / 2);
        margin-top: calc(-1 * $ballSize / 2);
        transform-origin: center;
    }
}

进阶 实现loading加载

复制代码
import React, { useEffect } from 'react';
import './index.scoped.scss';


const Test = () => {


    const arr = Array.from({ length: 32 }, (_, index) => index + 1);


    return <div className='flex items-center justify-center w-full h-[100vh] bg-[#5bbff1]'>

        <div className='relative rounded-full loading'>
            {arr.map((item, index) => {
                return <div key={index} className='absolute dot' />;
            })}
        </div>
    </div>;
};

export default Test;



// scss

$containSize: 150px;
$ballSize: 10px;

.loading {
    width: $containSize;
    height: $containSize;

    
    $n: 32; // 小球数量
    $pDeg: calc(360deg / $n);   // 每个小球旋转的角度


    .dot {
        width: $ballSize;
        height: $ballSize;
        top: 0;
        left: 50%;
        margin-left: calc(-1 * $ballSize / 2);
        margin-top: calc(-1 * $ballSize / 2);
        transform-origin: center calc($containSize / 2) + calc($ballSize / 2);
        
        $duration: 2s; // 小球动画总时长

        @for $i from 1 through $n {
            &:nth-child(#{$i}) {
                transform: rotate(calc($i - 1) * $pDeg);

                &::after,
                &::before {
                    animation-delay: -(calc($duration / $n * ($i - 1) * 6));
                }

            }
        }

        &::before,
        &::after {
            content: '';
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 100px;
        }

        perspective: 70px;
        transform-style: preserve-3d;

        &::before {
            top: -100%;
            background: #000;
            animation: rotate-black $duration infinite;

            @keyframes rotate-black {
                0% {
                    animation-timing-function: ease-in;
                }

                25% {
                    transform: translate3d(0, 100%, $ballSize);
                    animation-timing-function: ease-out;
                }

                50% {
                    transform: translate3d(0, 200%, 0);
                    animation-timing-function: ease-in;
                }

                75% {
                    transform: translate3d(0, 100%, -$ballSize);
                    animation-timing-function: ease-out;
                }
            }
        }

        &::after {
            top: 100%;
            background: #fff;
            animation: rotate-white $duration infinite;

            @keyframes rotate-white {
                0% {
                    animation-timing-function: ease-in;
                }

                25% {
                    transform: translate3d(0, -100%, -$ballSize);
                    animation-timing-function: ease-out;
                }

                50% {
                    transform: translate3d(0, -200%, 0);
                    animation-timing-function: ease-in;
                }

                75% {
                    transform: translate3d(0, -100%, $ballSize);
                    animation-timing-function: ease-out;
                }
            }
        }
    }
}
相关推荐
To_OC11 分钟前
LC 438 找到所有字母异位词:暴力超时后,我靠滑动窗口一招搞定
javascript·算法·leetcode
kyriewen1 小时前
面试官问"这段逻辑为什么这样写"——我才发现,这半年我写的代码,我自己都解释不了
前端·javascript·面试
一壶浊酒..2 小时前
Scrape Webpack练习
开发语言·javascript·webpack
命运之光2 小时前
【C语言完整代码】就诊信息管理系统
java·c语言·开发语言
命运之光3 小时前
【C语言完整代码】图书管理系统:图书馆场景下的增删改查实战
c语言·开发语言
猿长大人3 小时前
C# | Serilog 新手入门
开发语言·c#·.net·log
在世修行4 小时前
从零打造 C# 工业视觉检测系统(七):串口通信 SerialPort 封装与开发
开发语言·c#·modbus rtu·rs232/rs485
Hammer_Hans5 小时前
DFT笔记98
java·开发语言·数据库
默_笙5 小时前
⛵ 我用 React + TS 做了个"调色盘",顺便学会了企业级项目的目录架构
前端·javascript
渣波5 小时前
拒绝 Redux 样板代码:Zustand 核心原理与实战进阶指南(基础、异步与切片模式)
前端·javascript