📢 新文章推送 · 每周更新优质内容 · 订阅更新 →
向下滚动
游戏娱乐

侧边栏天气预报功能实现

AI 智能总结

前言

给博客加个天气预报,让访客一眼看到所在城市的实时天气,是个有趣又有用的小功能。本文记录从选型到落地的完整过程——最初尝试了和风天气,最终切换到完全免费的 Open-Meteo API,并把天气卡片放在了个人信息和公告之间的侧边栏位置。

效果概览

功能说明
🌍 IP 自动定位通过 ipapi.co 获取访客城市和坐标,无需手动选择
☀️ 实时天气Open-Meteo 免费 API,显示温度、天气图标和描述
📍 城市显示自动识别城市名,展示在天气卡片中
🌬️ 风向风力角度 → 中文风向(北/东北/东…),风速 → 蒲福风级
💧 湿度气压实时相对湿度 (%) 和海平面气压 (hPa)
👁 能见度实时能见度 (km)
💾 智能缓存localStorage 30 分钟缓存,减少 API 请求
🎨 暗色模式完整适配主题切换,CSS 变量驱动

技术选型

初选:和风天气

最初注册了和风天气开发者账号,尝试了两种方式:

  • 官方 Widgethe-plugin-simple):需要加载外部 JS,在导航栏宽度受限的情况下渲染不稳定,且 Widget Key 验证机制导致持续加载失败
  • API 直调/v7/weather/now):需要 JWT 或 API KEY 认证,浏览器端暴露密钥有安全风险

折腾了两轮之后,决定换一个免费、无需注册、零密钥的方案。

终选:Open-Meteo

Open-Meteo 是一个开源的免费天气 API:

  • ✅ 完全免费,无需 API Key
  • ✅ 全球覆盖,数据来源包括各国官方气象机构
  • ✅ 支持实时天气 + 预报
  • ✅ 支持 WMO 天气代码标准
  • ✅ 响应速度快,JSON 格式简洁

唯一的缺点是城市名需要额外获取(通过 ipapi.co 的 IP 定位解决)。

核心实现

数据流程

 1访客浏览器
 2 3    ├─ 1. ipapi.co/json  →  获取城市名 + 经纬度
 4 5    ├─ 2. localStorage   →  检查缓存(30分钟有效期)
 6    │                       ├─ 命中 → 直接渲染
 7    │                       └─ 未命中 ↓
 8 9    └─ 3. api.open-meteo.com/v1/forecast
10         → 传入经纬度 + 请求参数
11         → 返回实时天气 JSON
12         → 存入 localStorage + 渲染

天气代码映射

Open-Meteo 使用 WMO 天气代码,总共映射了 19 种常见天气到 emoji 图标和中文描述:

 1var weatherIcons = {
 2  0: '☀️',            // 晴
 3  1: '🌤️', 2: '⛅', 3: '☁️',  // 少云 / 多云 / 阴
 4  45: '🌫️', 48: '🌫️',       // 雾 / 雾凇
 5  51: '🌦️', 53: '🌦️', 55: '🌧️',  // 毛毛雨
 6  61: '🌧️', 63: '🌧️', 65: '🌧️',  // 小雨 / 中雨 / 大雨
 7  71: '❄️', 73: '❄️', 75: '❄️',  // 小雪 / 中雪 / 大雪
 8  80: '🌨️', 81: '🌨️', 82: '🌨️',  // 阵雨
 9  95: '⛈️', 96: '⛈️', 99: '⛈️'   // 雷暴
10};

风向风力计算

风向角度(0-360°)映射到 8 个中文方位:

1function windDir(deg) {
2  var dirs = ['北', '东北', '东', '东南', '南', '西南', '西', '西北'];
3  return dirs[Math.round(deg / 45) % 8] + '风';
4}

风速(km/h)按蒲福风级标准换算成 0-12 级:

风速 (km/h)风级描述
< 10 级无风
1-51 级软风
6-112 级轻风
12-193 级微风
20-284 级和风
29-385 级清风
39-496 级强风
50-617 级疾风
62-748 级大风
75-889 级烈风
89-10210 级狂风
103-11711 级暴风
≥ 11812 级飓风

侧边栏集成

天气卡片插入在个人信息(Profile)和公告(Announcement)之间,通过 Hugo 的 widget 排序机制控制:

1# hugo.toml
2[params.widgets]
3  order = ["profile", "weather", "announcement", ...]

模板结构:

1<div class="widget widget-weather">
2  <h4 class="widget-title">天气预报</h4>
3  <div class="weather-widget-body">
4    <!-- JS 动态渲染:图标 + 温度 + 描述 + 城市 -->
5  </div>
6  <div class="weather-widget-detail">
7    <!-- JS 动态渲染:风向/湿度/气压/能见度 -->
8  </div>
9</div>

缓存策略

 1var cacheTimeout = 30 * 60 * 1000; // 30 分钟
 2
 3// 优先读缓存
 4var cached = localStorage.getItem('lumin_weather_omet_v1');
 5if (cached) {
 6  var data = JSON.parse(cached);
 7  if (Date.now() - data.ts < cacheTimeout) {
 8    render(data);
 9    return; // 命中缓存,不发请求
10  }
11}

这样同一访客在 30 分钟内浏览多篇文章,只请求一次天气 API。

踩坑记录

和风天气 Widget 的坑

和风的 he-plugin-simple widget 在本地开发环境(localhost)下可能因为跨域或 Key 验证机制无法正常渲染,表现为无限「加载中」。即使换到生产环境,Widget Key 与 API Key 的权限体系也容易混淆。

导航栏空间不足

最初把天气放在导航栏搜索框旁边,但导航栏高度只有约 34px,和风 widget 在这个高度下文字渲染异常(只显示一个小白框)。侧边栏空间充裕,更适合展示完整的天气信息。

能见度单位转换

Open-Meteo 返回的能见度单位是(如 visibility: 10000),需要除以 1000 转换为公里显示。

配置说明

hugo.toml 中只需两个参数:

1[params.weather]
2  enable = true       # 总开关
3  cacheMinutes = 30   # 缓存时间(分钟)

无需填写任何 API Key,开箱即用。

总结

从和风天气折腾到 Open-Meteo,最终实现了一个零配置、零密钥、全免费的侧边栏天气预报。整个方案只有两个外部依赖:

  • ipapi.co — IP 定位(免费额度足够个人博客使用)
  • api.open-meteo.com — 实时天气数据(开源免费)

如果你也用 Hugo 搭建博客,可以参考这套方案快速集成天气功能。

版权声明

本文作者 Lumin

本文链接 https://www.zhengquan.xyz/game/weather-forecast/

许可协议 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

请作者喝杯咖啡 ☕

  • 微信打赏
    微信支付
  • 支付宝打赏
    支付宝
点击按钮查看打赏二维码
🎁 推荐工具
试试这些实用在线工具,提升工作效率
前往工具集 →

留言评论

期待你的想法

评论加载中