纯前端实现在网站上挂一个漂亮的天气标签。


天气来源
使用openweather提供的免费api,需注册帐号,生成api-key。
数据获取方式:
https://api.openweathermap.org/data/2.5/weather?q=beijing&appid=xxxxxxxx&units=metric&lang=zh_cn
或
https://api.openweathermap.org/data/2.5/weather?lat=39.91&lon=116.40&appid=xxxxxxxx&units=metric&lang=zh_cn
返回:
{"coord":{"lon":116.3972,"lat":39.9075},"weather":[{"id":800,"main":"Clear","description":"晴","icon":"01n"}],"base":"stations","main":{"temp":12.94,"feels_like":10.66,"temp_min":12.94,"temp_max":12.94,"pressure":1015,"humidity":14,"sea_level":1015,"grnd_level":1010},"visibility":10000,"wind":{"speed":2.96,"deg":297,"gust":8.78},"clouds":{"all":0},"dt":1745764328,"sys":{"type":1,"id":9609,"country":"CN","sunrise":1745702400,"sunset":1745751833},"timezone":28800,"id":1816670,"name":"Beijing","cod":200}
代码
徽章显示的地方:
<img id="weather-badge" src="">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <script> const LAT = 39.93; const LON = 119.59; const API_KEY = "xxxxxxxx"; const CITY_NAME = "今日天气";
async function updateWeatherBadge() { try { const apiUrl = `https://api.openweathermap.org/data/2.5/weather?lat=${LAT}&lon=${LON}&appid=${API_KEY}&units=metric&lang=zh_cn`; const response = await fetch(apiUrl); const data = await response.json(); const temp = Math.round(data.main.temp); const description = data.weather[0].description; let color; if (temp < 0) color = "lightblue"; else if (temp < 10) color = "blue"; else if (temp < 20) color = "green"; else if (temp < 30) color = "orange"; else color = "red"; const badgeUrl = `https://img.shields.io/badge/${encodeURIComponent(CITY_NAME)}-${temp}°C_${encodeURIComponent(description)}-${color}.svg`; document.getElementById("weather-badge").src = badgeUrl; } catch (error) { console.error("获取天气失败:", error); document.getElementById("weather-badge").src = "https://img.shields.io/badge/天气-加载失败-red.svg"; } }
updateWeatherBadge(); setInterval(updateWeatherBadge, 30 * 60 * 1000); </script>
|
优化
30分钟缓存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
| <a href="javascript:void(0)" onclick="forceRefreshWeather()" title="点击刷新"> <img id="weather-badge" src="https://img.shields.io/badge/天气-加载中-lightgrey.svg" alt="实时天气"> </a>
<script> const CONFIG = { LAT: 39.93, LON: 119.59, API_KEY: "xxxxxxxxxxx", CACHE_KEY: "weather_cache_v2", CACHE_TTL: 30 * 60 * 1000, RETRY_DELAY: 5000 };
async function updateWeather() { try { const cachedData = getValidCache(); if (cachedData) { renderBadge(cachedData); return; }
const apiUrl = `https://api.openweathermap.org/data/2.5/weather?lat=${CONFIG.LAT}&lon=${CONFIG.LON}&appid=${CONFIG.API_KEY}&units=metric&lang=zh_cn`; const response = await fetchWithTimeout(apiUrl, { timeout: 3000 }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); const processedData = processData(data); saveCache(processedData); renderBadge(processedData);
} catch (error) { console.error("[天气] 更新失败:", error); handleError(error); } }
function processData(apiData) { const temp = Math.round(apiData.main.temp); return { temp, desc: apiData.weather[0].description, color: getTempColor(temp), timestamp: Date.now() }; }
function getTempColor(temp) { if (temp < 0) return "lightblue"; if (temp < 10) return "blue"; if (temp < 20) return "green"; if (temp < 30) return "orange"; return "red"; }
function renderBadge(data) { const badgeUrl = `https://img.shields.io/badge/天气-${data.temp}°C_${encodeURIComponent(data.desc)}-${data.color}.svg?cacheBuster=${Date.now()}`; document.getElementById("weather-badge").src = badgeUrl; }
function getValidCache() { const raw = localStorage.getItem(CONFIG.CACHE_KEY); if (!raw) return null; try { const data = JSON.parse(raw); const isExpired = (Date.now() - data.timestamp) > CONFIG.CACHE_TTL; return isExpired ? null : data; } catch { return null; } }
function saveCache(data) { localStorage.setItem(CONFIG.CACHE_KEY, JSON.stringify(data)); }
function handleError(error) { const cached = getValidCache() || JSON.parse(localStorage.getItem(CONFIG.CACHE_KEY)); if (cached) { renderBadge(cached); console.warn("[天气] 使用缓存数据"); } else { document.getElementById("weather-badge").src = "https://img.shields.io/badge/天气-服务异常-red.svg"; } setTimeout(updateWeather, CONFIG.RETRY_DELAY); }
async function fetchWithTimeout(resource, { timeout = 5000 } = {}) { const controller = new AbortController(); const id = setTimeout(() => controller.abort(), timeout); const response = await fetch(resource, { signal: controller.signal }); clearTimeout(id); return response; }
function forceRefreshWeather() { localStorage.removeItem(CONFIG.CACHE_KEY); document.getElementById("weather-badge").src = "https://img.shields.io/badge/天气-刷新中-yellow.svg"; updateWeather(); }
document.addEventListener('DOMContentLoaded', () => { updateWeather(); setInterval(updateWeather, CONFIG.CACHE_TTL / 2); }); </script>
|