我使用 React 构建了一个模拟时钟,但秒针有问题。 秒针以顺时针方向开始,但一旦到达 59 秒标记,它就会逆时针移动,直到到达 1 秒标记。之后它再次顺时针移动。如何让它连续顺时针移动?
import React, { useEffect, useState } from 'react';
import './AnalogClock.css';
const AnalogClock = () => {
const [time, setTime] = useState(new Date());
useEffect(() => {
const interval = setInterval(() => {
const newTime = new Date();
setTime(newTime);
}, 1000);
return () => {
clearInterval(interval);
};
}, []);
const getRotation = (unit, max) => {
const value = time[`get${unit}`]();
let rotation = (value * 360) / max;
if (unit === 'Seconds') {
const seconds = value + time.getMilliseconds() / 1000;
rotation = (seconds * 6) % 360;
if (rotation < 0) {
rotation += 360;
}
}
return {
transform: `translate(-50%, -100%) rotate(${rotation}deg)`,
};
};
const renderNumbers = () => {
const numbers = [];
for (let i = 1; i <= 12; i++) {
const angle = (i * 30) * (Math.PI / 180);
const numberStyle = {
left: `calc(50% + ${Math.sin(angle) * 140}px)`,
top: `calc(50% - ${Math.cos(angle) * 140}px)`,
};
numbers.push(
<div key={i} className="number" style={numberStyle}>
{i}
</div>
);
}
return numbers;
};
return (
<div className="clock">
{renderNumbers()}
<div className="hour-hand" style={getRotation('Hours', 12)}></div>
<div className="minute-hand" style={getRotation('Minutes', 60)}></div>
<div
className="second-hand"
style={
time.getSeconds() === 59
? { ...getRotation('Seconds', 60), transition: 'none' }
: getRotation('Seconds', 60)
}
></div>
<div className="center-circle"></div>
</div>
);
};
export default AnalogClock;
不确定 css 是否有帮助,但它就在这里。
.clock {
position: relative;
width: 300px;
height: 300px;
border-radius: 50%;
background-color: #e0e0e0;
box-shadow: 20px 20px 40px rgba(0, 0, 0, 0.2), -20px -20px 40px rgba(255, 255, 255, 0.7);
padding: 20px;
}
.hour-hand,
.minute-hand,
.second-hand {
position: absolute;
background-color: #333;
transform-origin: bottom center;
transition: transform 0.5s ease-in-out;
box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.2), -4px -4px 8px rgba(255, 255, 255, 0.7);
}
.hour-hand {
width: 8px;
height: 90px;
top: 50%;
left: 50%;
transform: translate(-50%, -100%) translateX(-1px);
border-radius: 8px 8px 0 0;
}
.minute-hand {
width: 6px;
height: 120px;
top: 50%;
left: 50%;
transform: translate(-50%, -100%) translateX(-1px);
border-radius: 6px 6px 0 0;
}
.second-hand {
width: 4px;
height: 130px;
top: 50%;
left: 50%;
transform: translate(-50%, -100%) translateX(-1px);
border-radius: 4px 4px 0 0;
background-color: #ff0000;
}
.center-circle {
position: absolute;
top: 50%;
left: 50%;
width: 16px;
height: 16px;
background-color: #333;
border-radius: 50%;
transform: translate(-50%, -50%);
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2), -2px -2px 4px rgba(255, 255, 255, 0.7);
}
.number {
position: absolute;
font-size: 29px;
font-weight: bold;
color: #333;
transform: translate(-50%, -50%);
} Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
当你尝试在 css 中注入 js 来实现你的目标时,我建议你使用样式化组件来获得一些好处,将其提升到一个新的水平,并在 css 中使用 js 变量
代码的主要限制是您无法指定动画将永远继续,以便在达到 360 度时重新启动动画
这可以通过 css 关键帧和动画来实现,但如果不使用样式化组件,则很难将一些必要的参数传递给关键帧和动画,例如初始度数和完成循环的秒数
这或多或少是样式化组件的方法
import React, { useEffect, useState } from 'react'; import styled, { keyframes } from 'styled-components'; import './styles.css'; const rotate = (degree) => keyframes` from { transform: translate(-50%, -100%) rotate(${degree}deg); } to { transform: translate(-50%, -100%) rotate(${degree+360}deg); } ` const ClockStick = styled.div` animation: ${(props) => rotate(props.degree)} ${(props) => props.seconds}s linear; ` const App = () => { const [degrees, setDegrees] = useState({}); useEffect(() => { setDegrees({ hour: getRotation('Hours', 12), minute: getRotation('Minutes', 60), second: getRotation('Seconds', 60) }) }, []); const getRotation = (unit, max) => { const time = new Date(); const value = time[`get${unit}`](); const rotation = (value * 360) / max; return rotation; }; const renderNumbers = () => { const numbers = []; for (let i = 1; i <= 12; i++) { const angle = (i * 30) * (Math.PI / 180); const numberStyle = { left: `calc(50% + ${Math.sin(angle) * 140}px)`, top: `calc(50% - ${Math.cos(angle) * 140}px)`, }; numbers.push( <div key={i} className="number" style={numberStyle}> {i} </div> ); } return numbers; }; return ( <div className="clock"> {renderNumbers()} <ClockStick className="hour-hand" seconds={216000} degree={degrees.hour}></ClockStick> <ClockStick className="minute-hand" seconds={3600} degree={degrees.minute}></ClockStick> <ClockStick className="second-hand" seconds={60} degree={degrees.second} ></ClockStick> <div className="center-circle"></div> </div> ); }; export default App;我删除了一些不必要的逻辑,我将解释我添加的一些内容
这是结果
https://codesandbox.io/s/dawn-rgb-qn58t6
与答案相关的一些链接