React+less实现一个时钟效果

337 阅读2分钟

实现效果:

image.png

实现思路:

1.实现一个时钟效果,要包含三个用于显示时针、分针和秒针的div元素。使用React Hooks中的useStateuseEffect钩子配合实现时间的动态更新,然后计算出当前对应的时间的小时、分钟以及秒钟。然后使用less实现效果;

2.定义@duration@step两个变量,用来控制动画的时长和每一次旋转的角度。使用less中的keyframe()函数来创建名为rotate的动画,接下来要为时针、分针和秒针分别指定使用rotate动画,并传递不同的步数参数(分别为12、60和60),注意,使用keyframe()函数时,将动画名称作为第一个参数传入,并在其后面添加分号(例如keyframe(rotate; 60)),这样可以告诉less将其解析为动画名称,从而生成正确的css代码;

3.最后设置一个灰白色背景,以及圆形的样式,每个针的样式使用了绝对定位,通过设置top和left将其固定在时钟中间位置。

Clock.tsx

import React, { useEffect, useState } from "react";
import styles from './index.module.less';

const Clock = () => {
    const [time, setTime] = useState(new Date())

    useEffect(() => {
        const timer = clearInterval(() => {
            setTime(new Date())
        }, 1000)
        return () => {
            clearInterval(timer)
        }
    }, [])

    const hour = time.getHours() % 12 || 12;
    const minute = time.getMinutes();
    const second = time.getSeconds();

    return <>
        <div className={styles.clock}>
            <div className={styles.hour} style={{ transform: `rotate(${30 * hour}deg)` }}></div>
            <div className={styles.minute} style={{ transform: `rotate(${6 * minute}deg)` }}></div>
            <div className={styles.second} style={{ transform: `rotate(${6 * second}deg)` }}></div>
        </div>
    </>
}
            }

clock.module.less

    @duration: 1s;
    @step: 0.5;

    .keyframes(rotate; @duration, @step) {
        from {
            transform: rotate(0deg);
        }

        to {
            transform: rotate(@step * 360deg);
        }
    }

   .clock {
        width: 200px;
        height: 200px;
        border-radius: 50%;
        position: relative;
        background-color: #f6f6f6;
        position: relative;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
        border: 2px solid #e8e8e8;
        background-image: radial-gradient(circle at center, white 30%, #e8e8e8 180%);
        overflow: hidden;

        &::before {
            content: '';
            display: block;
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background-color: #333;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }

        .hour,
        .minute,
        .second {
            position: absolute;
            top: 50%;
            left: 50%;
            margin-left: -1px;
            transform-origin: bottom center;
            background-color: black;
        }

        .hour {
            width: 8px;
            height: 50px;
            background-color: #333;
            margin-top: -50px;
            box-shadow: 0 0 5px rgba(0, 0, 0, 0.4), 0 -3px 5px rgba(0, 0, 0, 0.2) inset;
            animation: keyframes(rotate, 12) linear infinite;
        }

        .minute {
            width: 6px;
            height: 70px;
            background-color: #333;
            margin-top: -70px;
            box-shadow: 0 0 5px rgba(0, 0, 0, 0.4), 0 -3px 5px rgba(0, 0, 0, 0.2) inset;
            animation: keyframes(rotate, 60) linear infinite;
        }

        .second {
            width: 2px;
            height: 90px;
            background-color: #d00;
            margin-top: -90px;
            box-shadow: 0 0 10px rgba(221, 0, 0, 0.4), 0 -3px 10px rgba(221, 0, 0, 0.2) inset;
            animation: keyframes(rotate, 60) linear infinite;
        }

    }