feat(components): 添加时间戳和日期时间转换功能

- 实现了时间戳实时显示组件,支持毫秒/秒单位切换和自动更新
- 添加了日期时间转时间戳转换器,支持多种时区选择和单位转换
- 实现了时间戳转日期时间转换器,支持毫秒/秒单位和时区转换
- 为App.css添加了响应式样式和时间戳组件相关样式
- 为时间戳和转换组件添加了错误处理和输入验证功能
- 实现在index.css中重置标题样式以保持一致性
This commit is contained in:
雨霖铃
2026-01-07 21:42:59 +08:00
parent 0cad722479
commit 11e941d5fe
5 changed files with 828 additions and 109 deletions
+135 -33
View File
@@ -1,45 +1,147 @@
import {useEffect, useState} from "react";
import {useEffect, useState, useRef, useCallback} from "react";
import CopyButton from "./CopyButton";
/**
* 时间戳显示和执行组件
*
* 功能特性:
* 1. 实时显示当前时间戳(毫秒/秒)
* 2. 支持毫秒和秒单位切换
* 3. 支持启动/停止时间戳自动更新
* 4. 提供复制时间戳功能
* 5. 响应式设计和良好的可访问性
*
* @component
* @example
* ```jsx
* <TimestampExecution />
* ```
*
* @returns {JSX.Element} 时间戳组件
*/
export function TimestampExecution() {
const [currentTimestamp, setCurrentTimestamp] = useState(Math.floor(Date.now()));
/** @type {[number, function]} 当前时间戳(毫秒)和更新函数 */
const [currentTimestamp, setCurrentTimestamp] = useState(() => Math.floor(Date.now()));
/** @type {[boolean, function]} 是否显示毫秒(true=毫秒,false=秒) */
const [showMilliseconds, setShowMilliseconds] = useState(true);
/** @type {[boolean, function]} 时间戳是否正在自动更新 */
const [isRunningTimestamp, setIsRunningTimestamp] = useState(true);
// 定时更新时间戳
/** @type {React.MutableRefObject<NodeJS.Timeout|null>} 定时器引用,用于清理 */
const timerRef = useRef(null);
/**
* 计算显示的时间戳值
* @type {number}
*/
const displayTimestamp = showMilliseconds
? currentTimestamp
: Math.floor(currentTimestamp / 1000);
/**
* 计算单位文本
* @type {string}
*/
const unitText = showMilliseconds ? '毫秒' : '秒';
/**
* 定时更新时间戳的副作用
* 根据 isRunningTimestamp 和 showMilliseconds 控制定时器的启停和间隔
*/
useEffect(() => {
const timerId = isRunningTimestamp ? setInterval(() => {
setCurrentTimestamp(Math.floor(Date.now()));
}, showMilliseconds ? 100 : 1000) : null;
// 清除之前的定时器
if (timerRef.current) {
clearInterval(timerRef.current);
timerRef.current = null;
}
return () => clearInterval(timerId);
// 如果需要运行,创建新的定时器
if (isRunningTimestamp) {
const interval = showMilliseconds ? 100 : 1000;
timerRef.current = setInterval(() => {
setCurrentTimestamp(Math.floor(Date.now()));
}, interval);
}
// 清理函数
return () => {
if (timerRef.current) {
clearInterval(timerRef.current);
timerRef.current = null;
}
};
}, [isRunningTimestamp, showMilliseconds]);
const toggleUnit = () => setShowMilliseconds(prev => !prev);
const toggleTimestamp = () => setIsRunningTimestamp(prev => !prev);
/**
* 切换时间戳显示单位(毫秒/秒)
* @type {function(): void}
*/
const toggleUnit = useCallback(() => {
setShowMilliseconds(prev => !prev);
}, []);
return (<div>
<h2>当前时间戳</h2>
<p>
<span>{Math.floor(currentTimestamp / (showMilliseconds ? 1 : 1000))}</span>
<span>{showMilliseconds ? '毫秒' : '秒'}</span>
</p>
<div>
<button type="button"
className="action-btn"
onClick={toggleUnit}
aria-label={showMilliseconds ? '切换为秒' : '切换为毫秒'}
>
切换单位
</button>
<CopyButton text={currentTimestamp.toString()} buttonText='复制'></CopyButton>
<button
type="button" // 明确指定类型,防止在 Form 中意外触发提交
className={`btn ${isRunningTimestamp ? 'stop-btn' : 'action-btn'}`}
onClick={toggleTimestamp}
aria-label={isRunningTimestamp ? '停止时间戳更新' : '开始时间戳更新'}
>
{isRunningTimestamp ? '停止' : '开始'}
</button>
/**
* 切换时间戳自动更新状态(启动/停止)
* @type {function(): void}
*/
const toggleTimestamp = useCallback(() => {
setIsRunningTimestamp(prev => !prev);
}, []);
/**
* 切换单位按钮的辅助文本
* @type {string}
*/
const unitButtonLabel = showMilliseconds ? '切换为秒显示' : '切换为毫秒显示';
/**
* 启动/停止按钮的辅助文本
* @type {string}
*/
const toggleButtonLabel = isRunningTimestamp ? '停止时间戳自动更新' : '开始时间戳自动更新';
/**
* 启动/停止按钮的显示文本
* @type {string}
*/
const toggleButtonText = isRunningTimestamp ? '停止' : '开始';
return (
<div className="timestamp-container">
<div className="timestamp-display">
<span className="timestamp-value">{displayTimestamp}</span>
<span className="timestamp-unit">{unitText}</span>
</div>
<div className="timestamp-controls">
<button
type="button"
className="timestamp-btn action-btn"
onClick={toggleUnit}
aria-label={unitButtonLabel}
title={unitButtonLabel}
>
切换单位
</button>
<CopyButton
text={currentTimestamp.toString()}
buttonText="复制时间戳"
aria-label="复制当前时间戳到剪贴板"
/>
<button
type="button"
className={`timestamp-btn ${isRunningTimestamp ? 'stop-btn' : 'action-btn'}`}
onClick={toggleTimestamp}
aria-label={toggleButtonLabel}
title={toggleButtonLabel}
>
{toggleButtonText}
</button>
</div>
</div>
</div>)
);
}