You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于本地时间切换页面类名:如何获取访客本地日出日落时间?

问题解答

一、代码运行性确认与优化

你的代码语法上可以运行,但存在逻辑漏洞:

  • 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 19:04:08