本文手把手教你正确解析 openweathermap api 返回的嵌套 json 对象,提取城市名、温度、湿度、风速等关键字段,并动态渲染到 html 表格中,同时规避初学者常见的异步执行、作用域、dom 操作等典型错误。
本文手把手教你正确解析 openweathermap api 返回的嵌套 json 对象,提取城市名、温度、湿度、风速等关键字段,并动态渲染到 html 表格中,同时规避初学者常见的异步执行、作用域、dom 操作等典型错误。
在前端开发中,从 RESTful API(如 OpenWeatherMap)获取 JSON 数据并结构化展示是核心技能之一。但许多初学者会遇到“数据能打印却无法提取”“控制台显示对象但报 undefined”“表格无反应或报错”等问题——根本原因往往不是 API 本身“混乱”,而是对 JSON 结构、Promise 执行时序和 DOM 操作逻辑理解不足。
以下是一个完整、可运行、已修复所有原始问题的教程实现:
✅ 正确结构:分离关注点 + 显式声明 + 同步 DOM 更新
首先,确保 HTML 中包含用户输入框与目标表格:
<label for="place">Enter a City Name:</label>
<input type="text" id="place" placeholder="e.g., London, Tokyo">
<button id="get-data-button">Get Weather</button>
<div id="error-message" style="color: red; margin-top: 8px;"></div>
<table id="weather" style="margin-top: 16px; border-collapse: collapse;">
<thead>
<tr>
<th style="border: 1px solid #333; padding: 8px;">City</th>
<th style="border: 1px solid #333; padding: 8px;">Temp (°C)</th>
<th style="border: 1px solid #333; padding: 8px;">Humidity (%)</th>
<th style="border: 1px solid #333; padding: 8px;">Wind Speed (m/s)</th>
</tr>
</thead>
<tbody></tbody>
</table>? 注意:我们使用 <tbody> 明确区分表头与数据行,便于后续 insertRow() 安全插入。
对应的 JavaScript(weather.js)如下:
const getDataButton = document.getElementById("get-data-button");
const placeInput = document.getElementById("place");
const tbody = document.querySelector("#weather tbody");
const errorMsg = document.getElementById("error-message");
// ✅ 关键:将 displayJson 定义为具名函数(非内联赋值),避免提升/作用域问题
function displayJson(data) {
// 清空上一次结果(可选,增强用户体验)
tbody.innerHTML = "";
// ✅ 正确提取 OpenWeatherMap 响应中的字段(查看文档可知结构)
const city = data.name || "Unknown";
const tempCelsius = parseFloat((data.main?.temp - 273.15).toFixed(2)) || 0;
const humidity = data.main?.humidity || 0;
const windSpeed = data.wind?.speed || 0;
// ✅ 安全插入新行:insertRow() → insertCell() 链式调用
const row = tbody.insertRow();
row.insertCell().textContent = city;
row.insertCell().textContent = `${tempCelsius}°C`;
row.insertCell().textContent = `${humidity}%`;
row.insertCell().textContent = `${windSpeed} m/s`;
}
// ✅ 错误处理:统一捕获网络、解析、业务逻辑异常
function handleError(error) {
errorMsg.textContent = `Error: ${error.message || 'Failed to fetch weather data.'}`;
console.error("Weather fetch failed:", error);
}
// ✅ 主逻辑:监听点击,读取输入,构建动态 URL(支持城市查询)
getDataButton.addEventListener("click", () => {
const cityName = placeInput.value.trim();
if (!cityName) {
handleError(new Error("Please enter a city name"));
return;
}
// ⚠️ 注意:实际使用需替换为你的有效 API Key,并启用 CORS 或后端代理
const apiKey = "30967b695a09a50b12dd726193281aa5";
const url = `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(cityName)}&appid=${apiKey}&units=metric`;
// ✅ Promise 链清晰:fetch → json() → displayJson;.catch 绑定在 promise 上
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
})
.then(displayJson)
.catch(handleError);
});? 关键知识点总结
| 问题类型 | 原始错误表现 | 正确做法 |
|---|---|---|
| 异步时序 | data.forEach(...) 在 .then() 外执行 → data 未定义 | 所有数据处理逻辑必须放在 .then() 回调或其调用的函数(如 displayJson)内部 |
| JSON 结构误判 | 把单个天气对象当数组遍历(.forEach),访问 post.title 等不存在字段 | 查阅 OpenWeatherMap 文档,确认响应是 { name, main: { temp, humidity }, wind: { speed } } 这类嵌套对象 |
| DOM 操作误区 | insertAdjacentHTML() 返回 undefined,却对其调用 .innerHTML 和 appendChild | 直接使用 insertRow() + insertCell(),或用 document.createElement() 构建元素后 appendChild() |
| 错误处理缺失 | .catch() 绑错对象(addEventListener 返回 undefined) | .catch() 必须链在 fetch().then(...) 的末尾,且建议检查 response.ok |
| 安全性与健壮性 | 未校验输入、未处理 null/undefined 字段、硬编码坐标 | 使用 ?. 可选链操作符、|| 默认值、encodeURIComponent() 编码城市名 |
✅ 进阶提示(下一步建议)
- ✨ 支持地理定位:用 navigator.geolocation.getCurrentPosition() 替代手动输入,获取用户实时经纬度;
- ? 添加加载状态:点击按钮后禁用按钮 + 显示 “Loading…” 提升体验;
- ? 美化 UI:引入图标(如晴天/雨天 SVG)、温度颜色渐变(冷蓝→暖红);
- ?️ 生产环境必备:API Key 不得暴露在前端;应通过自有后端代理请求,或使用服务端渲染(SSR)。
掌握从“看到 JSON”到“精准取值+稳定渲染”的全流程,是你跨越 JavaScript 初级陷阱、迈向可靠前端工程实践的关键一步。


















