<think>我们将使用HTML、CSS和JavaScript来创建一个可设置多组闹铃的闹钟。主要功能包括:
1. 显示当前时间。
2. 允许用户添加多个闹铃(设置小时、分钟和秒)。
3. 显示已设置的闹铃列表,并可以删除某个闹铃。
4. 当闹铃时间到达时,播放声音(或弹出提示)。
由于浏览器安全限制,自动播放声音可能需要用户首先与页面交互。因此,我们将在用户点击按钮时初始化音频。
设计思路:
- 使用HTML构建结构:当前时间显示、闹铃设置表单、闹铃列表。
- 使用CSS美化界面。
- 使用JavaScript实现:
a. 实时更新当前时间。
b. 添加闹铃:将用户设置的闹铃时间存储到数组中,并显示在列表中,每个闹铃项旁边有一个删除按钮。
c. 定时检查当前时间是否与任何闹铃时间匹配,匹配时触发提醒(这里使用alert和声音,实际中alert可能不太友好,但为了简单示例)。
d. 删除闹铃:从数组中移除并更新列表。
注意:为了避免同一闹铃重复触发,我们可以在触发后移除该闹铃,或者标记已触发,这里我们选择触发后移除。
我们将创建一个简单的音频元素,用于播放铃声。这里使用一个在线示例铃声(也可以使用本地文件)。
由于代码较长,我们将分部分构建。
步骤:
1. HTML结构
2. CSS样式
3. JavaScript功能
注意:在真实环境中,请考虑时区问题,这里我们使用本地时间。
代码实现如下:</think># 可设置多组闹铃的闹钟应用
我将为您创建一个功能完整的可设置多组闹铃的闹钟应用,包含添加、删除、启用/禁用闹铃功能,并提供响应式设计。
## 解决方案思路
1. **核心功能**:
- 实时显示当前时间
- 添加多个闹铃(设置时间、标签、重复选项)
- 管理闹铃(启用/禁用、删除)
- 闹铃触发时显示通知并播放声音
2. **技术实现**:
- 使用HTML/CSS构建界面
- 使用JavaScript实现闹钟逻辑
- 使用localStorage保存闹铃设置
- 使用Web Audio API播放铃声
下面是完整实现代码:
```html
<!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>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c);
color: white;
min-height: 100vh;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.container {
width: 100%;
max-width: 800px;
margin: 0 auto;
}
header {
text-align: center;
margin: 20px 0;
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 0 0 10px rgba(0,0,0,0.5);
}
.current-time {
font-size: 3.5rem;
font-weight: bold;
text-align: center;
padding: 20px;
background: rgba(0, 0, 0, 0.3);
border-radius: 15px;
margin: 20px 0;
box-shadow: 0 8px 16px rgba(0,0,0,0.3);
letter-spacing: 3px;
}
.alarm-controls {
background: rgba(255, 255, 255, 0.1);
padding: 25px;
border-radius: 15px;
margin-bottom: 30px;
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
input, select {
width: 100%;
padding: 12px;
border-radius: 8px;
border: none;
background: rgba(255, 255, 255, 0.9);
font-size: 1rem;
}
.days-container {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin-top: 10px;
}
.day-option {
flex: 1;
min-width: 40px;
text-align: center;
padding: 8px;
background: rgba(255, 255, 255, 0.2);
border-radius: 5px;
cursor: pointer;
transition: all 0.3s ease;
}
.day-option.selected {
background: #4CAF50;
font-weight: bold;
}
button {
background: #4CAF50;
color: white;
border: none;
padding: 14px 20px;
border-radius: 8px;
cursor: pointer;
font-size: 1.1rem;
font-weight: bold;
width: 100%;
margin-top: 10px;
transition: all 0.3s ease;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
button:hover {
background: #45a049;
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0,0,0,0.3);
}
.alarms-list {
background: rgba(255, 255, 255, 0.1);
border-radius: 15px;
padding: 20px;
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}
.alarms-list h2 {
text-align: center;
margin-bottom: 20px;
font-size: 1.8rem;
}
.alarm-item {
background: rgba(255, 255, 255, 0.15);
border-radius: 10px;
padding: 15px;
margin-bottom: 15px;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.3s ease;
}
.alarm-item.active {
border-left: 5px solid #4CAF50;
}
.alarm-item.inactive {
border-left: 5px solid #f44336;
opacity: 0.7;
}
.alarm-info {
flex-grow: 1;
}
.alarm-time {
font-size: 1.8rem;
font-weight: bold;
margin-bottom: 5px;
}
.alarm-label {
font-size: 1.1rem;
opacity: 0.9;
}
.alarm-days {
display: flex;
gap: 5px;
margin-top: 8px;
flex-wrap: wrap;
}
.alarm-day {
background: rgba(255, 255, 255, 0.2);
padding: 3px 8px;
border-radius: 20px;
font-size: 0.8rem;
}
.alarm-actions {
display: flex;
gap: 10px;
}
.toggle-btn, .delete-btn {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
}
.toggle-btn {
background: #4CAF50;
}
.toggle-btn.inactive {
background: #f44336;
}
.delete-btn {
background: #ff9800;
}
.toggle-btn:hover, .delete-btn:hover {
transform: scale(1.1);
}
.no-alarms {
text-align: center;
padding: 20px;
font-style: italic;
opacity: 0.7;
}
.notification {
position: fixed;
top: 20px;
right: 20px;
background: #4CAF50;
color: white;
padding: 15px 25px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
transform: translateX(120%);
transition: transform 0.5s ease;
z-index: 1000;
}
.notification.show {
transform: translateX(0);
}
@media (max-width: 600px) {
.current-time {
font-size: 2.5rem;
}
.alarm-item {
flex-direction: column;
align-items: flex-start;
}
.alarm-actions {
margin-top: 15px;
align-self: flex-end;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>多组闹铃闹钟</h1>
<p>设置和管理多个闹钟,不再错过重要事项</p>
</header>
<div class="current-time">
<span id="hours">00</span>:<span id="minutes">00</span>:<span id="seconds">00</span>
</div>
<div class="alarm-controls">
<h2>添加新闹铃</h2>
<div class="form-group">
<label for="alarm-time">闹铃时间</label>
<input type="time" id="alarm-time" required>
</div>
<div class="form-group">
<label for="alarm-label">闹铃标签</label>
<input type="text" id="alarm-label" placeholder="例如:晨起闹钟" maxlength="20">
</div>
<div class="form-group">
<label>重复</label>
<div class="days-container">
<div class="day-option" data-day="0">日</div>
<div class="day-option" data-day="1">一</div>
<div class="day-option" data-day="2">二</div>
<div class="day-option" data-day="3">三</div>
<div class="day-option" data-day="4">四</div>
<div class="day-option" data-day="5">五</div>
<div class="day-option" data-day="6">六</div>
</div>
</div>
<button id="add-alarm">添加闹铃</button>
</div>
<div class="alarms-list">
<h2>我的闹铃</h2>
<div id="alarms-container">
<!-- 闹铃将通过JS动态添加 -->
</div>
</div>
</div>
<div class="notification" id="notification">
<div id="notification-text">闹铃响了!</div>
<button id="dismiss-btn" style="margin-top:10px; background:#ff9800;">关闭</button>
</div>
<audio id="alarm-sound" loop>
<source src="https://assets.mixkit.co/sfx/preview/mixkit-alarm-digital-clock-beep-989.mp3" type="audio/mp3">
</audio>
<script>
// DOM元素
const hoursElement = document.getElementById('hours');
const minutesElement = document.getElementById('minutes');
const secondsElement = document.getElementById('seconds');
const addAlarmBtn = document.getElementById('add-alarm');
const alarmsContainer = document.getElementById('alarms-container');
const notification = document.getElementById('notification');
const notificationText = document.getElementById('notification-text');
const dismissBtn = document.getElementById('dismiss-btn');
const alarmSound = document.getElementById('alarm-sound');
// 闹铃数组
let alarms = JSON.parse(localStorage.getItem('alarms')) || [];
// 星期选项
const dayOptions = document.querySelectorAll('.day-option');
let selectedDays = [];
// 初始化 - 更新时间和渲染闹铃
updateTime();
setInterval(updateTime, 1000);
renderAlarms();
checkAlarms();
setInterval(checkAlarms, 1000);
// 更新时间显示
function updateTime() {
const now = new Date();
hoursElement.textContent = String(now.getHours()).padStart(2, '0');
minutesElement.textContent = String(now.getMinutes()).padStart(2, '0');
secondsElement.textContent = String(now.getSeconds()).padStart(2, '0');
}
// 添加星期选择事件
dayOptions.forEach(option => {
option.addEventListener('click', () => {
const day = option.getAttribute('data-day');
if (option.classList.contains('selected')) {
option.classList.remove('selected');
selectedDays = selectedDays.filter(d => d !== day);
} else {
option.classList.add('selected');
selectedDays.push(day);
}
// 排序
selectedDays.sort();
});
});
// 添加闹铃
addAlarmBtn.addEventListener('click', () => {
const alarmTimeInput = document.getElementById('alarm-time').value;
const alarmLabelInput = document.getElementById('alarm-label').value || '闹铃';
if (!alarmTimeInput) {
alert('请选择闹铃时间');
return;
}
// 解析时间
const [hours, minutes] = alarmTimeInput.split(':').map(Number);
// 创建新闹铃对象
const newAlarm = {
id: Date.now(),
hours: hours,
minutes: minutes,
label: alarmLabelInput,
days: [...selectedDays],
active: true
};
// 添加到数组
alarms.push(newAlarm);
saveAlarms();
renderAlarms();
// 重置表单
document.getElementById('alarm-time').value = '';
document.getElementById('alarm-label').value = '';
dayOptions.forEach(option => option.classList.remove('selected'));
selectedDays = [];
});
// 保存闹铃到localStorage
function saveAlarms() {
localStorage.setItem('alarms', JSON.stringify(alarms));
}
// 渲染闹铃列表
function renderAlarms() {
if (alarms.length === 0) {
alarmsContainer.innerHTML = '<div class="no-alarms">没有闹铃,请添加一个闹铃</div>';
return;
}
// 按时间排序
alarms.sort((a, b) => {
if (a.hours !== b.hours) return a.hours - b.hours;
return a.minutes - b.minutes;
});
alarmsContainer.innerHTML = '';
alarms.forEach(alarm => {
const alarmElement = document.createElement('div');
alarmElement.className = `alarm-item ${alarm.active ? 'active' : 'inactive'}`;
const timeStr = `${String(alarm.hours).padStart(2, '0')}:${String(alarm.minutes).padStart(2, '0')}`;
// 显示重复日期
let daysDisplay = '';
if (alarm.days.length > 0) {
daysDisplay = '<div class="alarm-days">';
alarm.days.forEach(day => {
const dayNames = ['日', '一', '二', '三', '四', '五', '六'];
daysDisplay += `<span class="alarm-day">${dayNames[day]}</span>`;
});
daysDisplay += '</div>';
}
alarmElement.innerHTML = `
<div class="alarm-info">
<div class="alarm-time">${timeStr}</div>
<div class="alarm-label">${alarm.label}</div>
${daysDisplay}
</div>
<div class="alarm-actions">
<div class="toggle-btn ${alarm.active ? '' : 'inactive'}" data-id="${alarm.id}">
${alarm.active ? '✓' : '✗'}
</div>
<div class="delete-btn" data-id="${alarm.id}">✕</div>
</div>
`;
alarmsContainer.appendChild(alarmElement);
});
// 添加事件监听器
document.querySelectorAll('.toggle-btn').forEach(btn => {
btn.addEventListener('click', toggleAlarm);
});
document.querySelectorAll('.delete-btn').forEach(btn => {
btn.addEventListener('click', deleteAlarm);
});
}
// 切换闹铃激活状态
function toggleAlarm(e) {
const id = parseInt(e.target.getAttribute('data-id'));
const alarm = alarms.find(a => a.id === id);
if (alarm) {
alarm.active = !alarm.active;
saveAlarms();
renderAlarms();
}
}
// 删除闹铃
function deleteAlarm(e) {
const id = parseInt(e.target.getAttribute('data-id'));
alarms = alarms.filter(a => a.id !== id);
saveAlarms();
renderAlarms();
}
// 检查闹铃是否应该触发
function checkAlarms() {
const now = new Date();
const currentDay = now.getDay().toString(); // 0 = 星期日
const currentHours = now.getHours();
const currentMinutes = now.getMinutes();
alarms.forEach(alarm => {
if (!alarm.active) return;
// 检查日期
const dayMatch = alarm.days.length === 0 || alarm.days.includes(currentDay);
// 检查时间
const timeMatch = alarm.hours === currentHours && alarm.minutes === currentMinutes;
if (dayMatch && timeMatch && now.getSeconds() === 0) {
triggerAlarm(alarm);
}
});
}
// 触发闹铃
function triggerAlarm(alarm) {
notificationText.textContent = `⏰ ${alarm.label} ⏰ ${alarm.hours}:${String(alarm.minutes).padStart(2, '0')}`;
notification.classList.add('show');
// 播放声音
alarmSound.currentTime = 0;
alarmSound.play();
}
// 关闭通知
dismissBtn.addEventListener('click', () => {
notification.classList.remove('show');
alarmSound.pause();
});
</script>
</body>
</html>
```
## 代码功能说明
这个闹钟应用具有以下核心功能:
1. **实时时钟显示**:
- 使用JavaScript的Date对象获取当前时间
- 每秒更新一次显示
2. **添加闹铃**:
- 用户可以设置闹铃时间(小时和分钟)
- 可以添加闹铃标签(如"晨起闹钟")
- 可选择重复日期(周一至周日)
3. **闹铃管理**:
- 显示所有已设置的闹铃
- 可以启用/禁用闹铃(绿色表示启用,红色表示禁用)
- 可以删除不需要的闹铃
4. **闹铃触发**:
- 当到达设定时间时,显示通知并播放提示音
- 用户可以关闭通知和声音
5. **数据持久化**:
- 使用localStorage保存所有闹铃设置
- 页面刷新后闹铃设置不会丢失
## 技术细节
1. **时间处理**:
- 使用JavaScript的Date对象获取当前时间
- 使用setInterval每秒更新一次显示
2. **闹铃存储**:
- 使用数组存储所有闹铃对象
- 每个闹铃对象包含时间、标签、重复日期和激活状态
- 使用localStorage保存数据
3. **用户界面**:
- 响应式设计,适配不同屏幕尺寸
- 使用CSS渐变和阴影创建现代化界面
- 使用CSS动画增强用户体验
4. **声音播放**:
- 使用HTML5 Audio元素播放提示音
- 当闹铃触发时循环播放声音
5. **通知系统**:
- 使用CSS动画实现通知滑入效果
- 提供关闭按钮停止声音和隐藏通知
## 使用说明
1. 在"添加新闹铃"区域设置闹铃时间和标签
2. 选择重复日期(可选)
3. 点击"添加闹铃"按钮
4. 在闹铃列表中可以启用/禁用或删除闹铃
5. 当闹铃触发时,右上角会显示通知并播放声音
这个应用完全在浏览器中运行,不需要任何服务器支持,所有数据都保存在用户的本地浏览器中。