纯html无法实现可靠用药提醒,必须用javascript控制定时器与音频播放;需用户首次点击激活音频上下文,用settimeout精准调度而非setinterval轮询,结合notification api(需授权)和localstorage持久化用药时间,并通过本地服务器测试音频。

怎么用 HTML + JavaScript 实现一个能真正响铃提醒的用药页面
纯 HTML 无法触发系统级提醒(比如弹窗+声音),必须配合 JavaScript 控制定时器和音频播放。关键不是“页面长什么样”,而是“到点能不能可靠触发”。很多所谓“用药提醒页”点开就失效,原因就是没处理浏览器自动播放策略或定时器被休眠。
- 浏览器(尤其 Chrome、Safari)默认禁止自动播放
audio,必须由用户手势(如点击)首次激活音频上下文 -
setTimeout和setInterval在标签页非活跃状态(切换 tab、锁屏)下可能被大幅降频甚至暂停,不能依赖它做精确到分钟的提醒 - 真要可靠提醒,得用
Notification API(需用户授权)+ 手动播放音频(首次点击后才可自动播) - 示例初始化逻辑:
let audio = new Audio('alarm.mp3');<br>document.body.addEventListener('click', () => {<br> audio.play().catch(e => console.log('请先点击页面以启用声音'));<br>}, { once: true });
如何保存用户设置的用药时间(不用后端也能持久化)
本地存储用 localStorage 最直接,但要注意:它只存字符串,且不同用药项不能简单用同一个 key 覆盖。
- 每个用药项建议用唯一 ID(如
med_12345)作为 key,值存为 JSON 字符串:{"name":"阿司匹林","time":"08:00","enabled":true} - 读取时务必加
try/catch,因为用户可能手动清空或数据损坏:try {<br> const data = JSON.parse(localStorage.getItem('med_12345') || '{}');<br>} catch (e) { /* 降级处理 */ } - 避免直接存 Date 对象——序列化后变字符串,再解析易出错;统一用
HH:mm格式字符串存时间
为什么 setInterval 检查时间会漏提醒?替代方案是什么
每分钟跑一次 setInterval 看当前时间是否匹配,看似简单,实则高危:页面关闭、睡眠、系统时间跳变都会导致错过。
- 更稳妥的做法是:每次页面加载时,遍历所有启用的用药项,计算「距离下次提醒还有多少毫秒」,然后用单次
setTimeout精准调度 - 例如现在是
07:58,用药设在08:00,就setTimeout(remind, 2 * 60 * 1000),而不是每分钟轮询 - 提醒触发后,立刻重新计算「下一次」时间(考虑每日重复),再设下一个
setTimeout - 这样即使页面关掉再打开,只要没超时,仍能补上最近一次该触发的提醒
移动端 Safari 上 Notification 不弹出?这是权限和时机问题
Safari 对 Notification.requestPermission() 卡得最严:必须在用户点击等同步事件中调用,且不能在异步回调(如 setTimeout、fetch 后)里触发。
- 正确做法:放一个「开启提醒」按钮,点击时立即调用
Notification.requestPermission() - 拿到
'granted'后,再把权限状态存进localStorage,避免反复申请 - 实际触发提醒时,必须确保
new Notification(...)在用户操作后的 30 秒内执行(Safari 限制),所以不要把它塞进延迟函数里 - 如果权限被拒,退而求其次用页面内
alert()或顶部 banner(position: fixed),别留白等待
实际部署时最容易被忽略的是音频文件路径和跨域问题:audio.src 必须是同源或允许 CORS 的地址,本地双击打开 HTML 文件(file:// 协议)下绝大多数音频会静音——必须起一个本地服务(如 python3 -m http.server)来测试。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











