纯前端显示天气
纯前端实现在网站上挂一个漂亮的天气标签。
天气来源
使用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="">
<script>
// 配置
const LAT = 39.93; //经纬度
const LON = 119.59;
const API_KEY = "xxxxxxxx"; // 替换为你的API密钥
const CITY_NAME = "今日天气"; // 自定义显示名称
async function updateWeatherBadge() {
try {
// 1. 获取天气数据
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;
// 2. 根据温度选择颜色
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";
// 3. 生成 Shields.io 徽章 URL
const badgeUrl = `https://img.shields.io/badge/${encodeURIComponent(CITY_NAME)}-${temp}°C_${encodeURIComponent(description)}-${color}.svg`;
// 4. 更新徽章
document.getElementById("weather-badge").src = badgeUrl;
} catch (error) {
console.error("获取天气失败:", error);
// 显示错误徽章
document.getElementById("weather-badge").src =
"https://img.shields.io/badge/天气-加载失败-red.svg";
}
}
// 初始加载 + 每30分钟更新一次
updateWeatherBadge();
setInterval(updateWeatherBadge, 30 * 60 * 1000);
</script>
优化
30分钟缓存:
<!-- 徽章容器(支持点击刷新) -->
<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, // 30分钟缓存
RETRY_DELAY: 5000 // 失败后5秒重试
};
// ===== 核心函数 =====
async function updateWeather() {
try {
// 1. 检查缓存是否有效
const cachedData = getValidCache();
if (cachedData) {
renderBadge(cachedData);
return;
}
// 2. 调用API获取新数据
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);
// 3. 更新缓存和界面
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();
// 定时检查(实际更新取决于缓存TTL)
setInterval(updateWeather, CONFIG.CACHE_TTL / 2);
});
</script>