我想制作一个番茄时钟的页面,可以自定义专注时长(默认为 25 分钟)和休息时长(默认为 5 分钟)。点击 “开始” 按钮后,能够以倒计时的方式,精确显示当前计时剩余时间,每秒进行实时更新,时间格式为 “分:秒”。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>番茄工作时钟</title>
<style>
:root {
--primary: #e74c3c;
--secondary: #2ecc71;
--bg: #f8f9fa;
--card: #ffffff;
--text: #333333;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: var(--bg);
padding: 20px;
transition: background 0.5s ease;
}
.container {
width: 100%;
max-width: 500px;
text-align: center;
}
.card {
background: var(--card);
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
padding: 40px 30px;
margin-bottom: 20px;
}
.timer-display {
font-size: 5rem;
font-weight: 700;
font-family: 'Courier New', monospace;
margin: 30px 0;
color: var(--text);
}
.status {
font-size: 1.8rem;
margin-bottom: 30px;
font-weight: 600;
}
.work { color: var(--primary); }
.break { color: var(--secondary); }
.controls {
display: flex;
justify-content: center;
gap: 15px;
margin: 20px 0;
}
button {
padding: 12px 30px;
font-size: 1.1rem;
border: none;
border-radius: 50px;
cursor: pointer;
font-weight:600;
transition: all 0.3s ease;
}
.btn-start {
background: var(--primary);
color: white;
}
.btn-pause {
background: #f39c12;
color: white;
}
.btn-reset {
background: #7f8c8d;
color: white;
}
button:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.settings {
display: flex;
justify-content: center;
gap: 30px;
margin-top: 30px;
}
.setting-group {
display: flex;
flex-direction: column;
align-items: center;
}
.setting-group label {
margin-bottom: 8px;
font-weight: 500;
color: #555;
}
.setting-controls {
display: flex;
align-items: center;
gap: 10px;
}
.setting-controls button {
width: 40px;
height: 40px;
padding: 0;
border-radius: 50%;
font-size: 1.2rem;
display: flex;
justify-content: center;
align-items: center;
}
.time-value {
font-size: 1.5rem;
font-weight: 600;
min-width: 40px;
}
@media (max-width: 480px) {
.timer-display { font-size: 3.5rem; }
.settings { flex-direction: column; gap: 20px; }
}
</style>
</head>
<body>
<div class="container">
<div class="card">
<div class="status work">专注时间</div>
<div class="timer-display">25:00</div>
<div class="controls">
<button class="btn-start">开始</button>
<button class="btn-pause">暂停</button>
<button class="btn-reset">重置</button>
</div>
<div class="settings">
<div class="setting-group">
<label>专注时长 (分钟)</label>
<div class="setting-controls">
<button class="decrease-work">-</button>
<div class="time-value" id="work-duration">25</div>
<button class="increase-work">+</button>
</div>
</div>
<div class="setting-group">
<label>休息时长 (分钟)</label>
<div class="setting-controls">
<button class="decrease-break">-</button>
<div class="time-value" id="break-duration">5</div>
<button class="increase-break">+</button>
</div>
</div>
</div>
</div>
</div>
<script>
const timerDisplay = document.querySelector('.timer-display');
const statusDisplay = document.querySelector('.status');
const startBtn = document.querySelector('.btn-start');
const pauseBtn = document.querySelector('.btn-pause');
const resetBtn = document.querySelector('.btn-reset');
const workDurationEl = document.getElementById('work-duration');
const breakDurationEl = document.getElementById('break-duration');
const decreaseWorkBtn = document.querySelector('.decrease-work');
const increaseWorkBtn = document.querySelector('.increase-work');
const decreaseBreakBtn = document.querySelector('.decrease-break');
const increaseBreakBtn = document.querySelector('.increase-break');
let workDuration = 25;
let breakDuration = 5;
let secondsLeft = workDuration * 60;
let timerInterval = null;
let isRunning = false;
let isWorkTime = true;
function updateDisplay() {
const minutes = Math.floor(secondsLeft / 60);
const seconds = secondsLeft % 60;
timerDisplay.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
}
function startTimer() {
if (isRunning) return;
isRunning = true;
timerInterval = setInterval(() => {
secondsLeft--;
updateDisplay();
if (secondsLeft <= 0) {
clearInterval(timerInterval);
isRunning = false;
isWorkTime = !isWorkTime;
statusDisplay.textContent = isWorkTime ? '专注时间' : '休息时间';
statusDisplay.className = `status ${isWorkTime ? 'work' : 'break'}`;
secondsLeft = (isWorkTime ? workDuration : breakDuration) * 60;
updateDisplay();
document.body.style.background = isWorkTime
? 'linear-gradient(135deg, #f8f9fa, #e9ecef)'
: 'linear-gradient(135deg, #d1f2eb, #a9dfbf)';
setTimeout(startTimer, 1000);
}
}, 1000);
}
function pauseTimer() {
if (!isRunning) return;
clearInterval(timerInterval);
isRunning = false;
}
function resetTimer() {
pauseTimer();
isWorkTime = true;
secondsLeft = workDuration * 60;
statusDisplay.textContent = '专注时间';
statusDisplay.className = 'status work';
document.body.style.background = 'linear-gradient(135deg, #f8f9fa, #e9ecef)';
updateDisplay();
}
function updateWorkDuration(value) {
workDuration = Math.max(1, Math.min(60, workDuration + value));
workDurationEl.textContent = workDuration;
if (!isRunning && isWorkTime) {
secondsLeft = workDuration * 60;
updateDisplay();
}
}
function updateBreakDuration(value) {
breakDuration = Math.max(1, Math.min(30, breakDuration + value));
breakDurationEl.textContent = breakDuration;
if (!isRunning && !isWorkTime) {
secondsLeft = breakDuration * 60;
updateDisplay();
}
}
startBtn.addEventListener('click', startTimer);
pauseBtn.addEventListener('click', pauseTimer);
resetBtn.addEventListener('click', resetTimer);
decreaseWorkBtn.addEventListener('click', () => updateWorkDuration(-1));
increaseWorkBtn.addEventListener('click', () => updateWorkDuration(1));
decreaseBreakBtn.addEventListener('click',() => updateBreakDuration(-1));
increaseBreakBtn.addEventListener('click', () => updateBreakDuration(1));
updateDisplay();
</script>
</body>
</html>