基于本地时间切换页面类名:如何获取访客本地日出日落时间?
问题解答
一、代码运行性确认与优化
你的代码语法上可以运行,但存在逻辑漏洞:
- 20点整设置
inter类,但20:01~22:59期间,getHours()返回20/21/22,会进入else分支最终设置day类,和“日落后进入夜间”的预期不符。 - 原代码每小时执行一次切换,用户打开页面若不是整点,会延迟到下一个整点才触发后续切换(虽有初始化调用,但后续切换依赖整点)。
优化后的修复版代码:
setInterval(change_background, 1000 * 60); // 改为每分钟检查一次,避免整点延迟 function change_background() { const d = new Date(); const hours = d.getHours(); const minutes = d.getMinutes(); const introEl = document.getElementById("intro"); // 修正逻辑:6点整为过渡,6:01~19:59为白天,20点整为过渡,20:01~次日5:59为夜间 if (hours === 6 && minutes === 0) { introEl.className = "inter"; } else if (hours === 20 && minutes === 0) { introEl.className = "inter"; } else if (hours >= 6 && hours < 20) { introEl.className = "day"; } else { introEl.className = "night"; } } change_background();
二、替换固定时间为本地实际日出日落
要实现这个需求,需分三步完成:
1. 获取访客地理位置经纬度
通过浏览器Geolocation API获取用户经纬度(需用户授权):
function getGeolocation() { return new Promise((resolve, reject) => { if (!navigator.geolocation) { reject("浏览器不支持地理位置功能"); return; } navigator.geolocation.getCurrentPosition( (pos) => resolve({ lat: pos.coords.latitude, lon: pos.coords.longitude }), (err) => reject(err.message) ); }); }
2. 根据经纬度计算本地日出日落时间
使用天文公式直接在前端计算(无需第三方服务):
// 根据经纬度、日期计算本地日出日落时间(返回带小数的小时数,如6.25表示6:15) function calculateSunriseSunset(lat, lon, date = new Date()) { const dayOfYear = Math.floor((date - new Date(date.getFullYear(), 0, 0)) / (1000 * 60 * 60 * 24)); const radLat = lat * Math.PI / 180; const radLon = lon * Math.PI / 180; const declination = 23.45 * Math.sin((2 * Math.PI / 365) * (dayOfYear - 81)); // 计算日出日落的小时角 const hourAngleSunrise = Math.acos( Math.cos(Math.PI / 2) / Math.cos(radLat) / Math.cos(declination) - Math.tan(radLat) * Math.tan(declination) ); const hourAngleSunset = -hourAngleSunrise; // 转换为本地时间(UTC+时区偏移) const utcSunrise = 12 + (hourAngleSunrise * 180 / Math.PI) / 15 - lon / 15; const utcSunset = 12 + (hourAngleSunset * 180 / Math.PI) / 15 - lon / 15; const timeZoneOffset = date.getTimezoneOffset() / 60; // 时区偏移(小时,西为正,东为负) return { sunrise: utcSunrise - timeZoneOffset, sunset: utcSunset - timeZoneOffset }; }
3. 整合到背景切换逻辑
将上述代码整合,实现完整的动态切换功能,同时保留固定时间作为降级方案:
async function initBackgroundSwitch() { try { // 获取经纬度 const { lat, lon } = await getGeolocation(); // 计算当日日出日落时间 let { sunrise, sunset } = calculateSunriseSunset(lat, lon); // 每天重新计算一次日出日落(日期变化时更新时间) setInterval(() => { const newDate = new Date(); ({ sunrise, sunset } = calculateSunriseSunset(lat, lon, newDate)); }, 1000 * 60 * 60 * 24); // 每分钟检查一次时间,切换背景 setInterval(changeBackground, 1000 * 60); // 初始化切换 changeBackground(); function changeBackground() { const now = new Date(); const currentHours = now.getHours() + now.getMinutes() / 60; // 当前时间转为小时小数 const introEl = document.getElementById("intro"); // 日出日落前后10分钟设为过渡(可自行调整时长) const sunriseStart = sunrise - 10/60; const sunriseEnd = sunrise + 10/60; const sunsetStart = sunset - 10/60; const sunsetEnd = sunset + 10/60; if (currentHours >= sunriseStart && currentHours <= sunriseEnd) { introEl.className = "inter"; } else if (currentHours >= sunsetStart && currentHours <= sunsetEnd) { introEl.className = "inter"; } else if (currentHours > sunriseEnd && currentHours < sunsetStart) { introEl.className = "day"; } else { introEl.className = "night"; } } } catch (err) { console.error("获取地理位置失败,使用默认时间切换:", err); // 降级到原固定时间逻辑 setInterval(changeBackgroundFallback, 1000 * 60); changeBackgroundFallback(); function changeBackgroundFallback() { const d = new Date(); const hours = d.getHours(); const minutes = d.getMinutes(); const introEl = document.getElementById("intro"); if (hours === 6 && minutes === 0) { introEl.className = "inter"; } else if (hours === 20 && minutes === 0) { introEl.className = "inter"; } else if (hours >= 6 && hours < 20) { introEl.className = "day"; } else { introEl.className = "night"; } } } } // 启动功能 initBackgroundSwitch();
说明
- 该实现会请求用户授权地理位置,若用户拒绝或浏览器不支持,自动降级为原固定时间逻辑。
- 日出日落的过渡时长可自行调整,修改
10/60即可(比如5/60代表5分钟)。 - 每天自动重新计算日出日落时间,保证日期变化时的准确性。
内容的提问来源于stack exchange,提问作者arihel0
相关产品推荐
相关产品推荐

