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

如何在基于OpenWeatherMap API的JS天气应用中限制搜索美国城市并处理日温数据

问题描述

我为课程作业开发了一款基于OpenWeatherMap API的极简天气应用,目前面临两个技术问题:

  1. 按要求使用5-day/3-hour forecast API展示未来5天的最高/最低气温、湿度、天气状况及对应图标,但该API以3小时为间隔返回数据,无法直接获取每日的最高、最低气温,当前手动创建每日元素并取固定索引数据的方式十分笨拙;
  2. 需要将城市搜索范围限制为美国城市,但不清楚如何在JavaScript中实现,也未找到API调用时的对应参数设置方法。

当前应用代码如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Weather app</title>
  </head>
  <body>
    <h1>Weather forecast</h1>
    <form id="cityForm">
      <label for="city">Enter City Name:</label>
      <input type="text" id="city" name="city" />
      <br /><br />
      <input type="submit" value="Submit" />
    </form>
    <div id="output"></div>
    <script>
      function getWeather(query) {
        var url =
          "http://api.openweathermap.org/data/2.5/forecast?q=" +
          query +
          "&units=imperial&APPID=56866f8407bb1e2d63330f3c046f35af";
        fetch(url)
          .then((response) => response.json())
          .then((data) => displayWeather(data)); //call displayWeather function
      }

      document
        .getElementById("cityForm")
        .addEventListener("submit", function (event) {
          event.preventDefault(); // prevent the form from submitting
          var city = document.getElementById("city").value; // get the city name from the input field
          getWeather(city);
        });

      function displayWeather(weather) {
        console.log(weather);
        var resultContainer = document.querySelector("#output");
        var cityName = document.createElement("h2");
        resultContainer.append(cityName);
        var forecastDate1 = document.createElement("p"); // Creating elements
        var forecastDate2 = document.createElement("p");
        var forecastDate3 = document.createElement("p");
        var forecastDate4 = document.createElement("p");
        var forecastDate5 = document.createElement("p");
        cityName.textContent = weather.city.name;
        var icon = document.createElement("img");
        var iconUrl =
          "http://openweathermap.org/img/w/" +
          weather.list[0].weather[0].icon +
          ".png";
        icon.setAttribute("src", iconUrl);

        var description = document.createElement("p");
        var day1 = new Date(weather.list[0].dt * 1000);
        const month1 = day1.getMonth() + 1;
        const firstDay = day1.getDate();
        const year1 = day1.getFullYear();
        const outputDateStr1 = `${month1.toString().padStart(2, "0")}/${firstDay
          .toString()
          .padStart(2, "0")}/${year1.toString()}`;

        var day2 = new Date(weather.list[8].dt * 1000);
        const month2 = day2.getMonth() + 1;
        const secondDay = day2.getDate();
        const year2 = day2.getFullYear();
        const outputDateStr2 = `${month2
          .toString()
          .padStart(2, "0")}/${secondDay
          .toString()
          .padStart(2, "0")}/${year2.toString()}`;

        var day3 = new Date(weather.list[16].dt * 1000);
        const month3 = day3.getMonth() + 1;
        const thirdDay = day3.getDate();
        const year3 = day3.getFullYear();
        const outputDateStr3 = `${month3.toString().padStart(2, "0")}/${thirdDay
          .toString()
          .padStart(2, "0")}/${year3.toString()}`;

        var day4 = new Date(weather.list[24].dt * 1000);
        const month4 = day4.getMonth() + 1;
        const fourthDay = day4.getDate();
        const year4 = day4.getFullYear();
        const outputDateStr4 = `${month4
          .toString()
          .padStart(2, "0")}/${fourthDay
          .toString()
          .padStart(2, "0")}/${year4.toString()}`;

        var day5 = new Date(weather.list[32].dt * 1000);
        const month5 = day5.getMonth() + 1;
        const fifthDay = day5.getDate();
        const year5 = day5.getFullYear();
        const outputDateStr5 = `${month5.toString().padStart(2, "0")}/${fifthDay
          .toString()
          .padStart(2, "0")}/${year5.toString()}`;

        forecastDate1.textContent = `${outputDateStr1} 
        Min ${weather.list[0].main.temp_min} F 
        Max: ${weather.list[0].main.temp_max} F 
        Humidity: ${weather.list[0].main.humidity}% 
        Weather conditions: ${weather.list[0].weather[0].description}`;
        var icon1 = document.createElement("img");
        var iconUrl1 =
          "http://openweathermap.org/img/w/" +
          weather.list[0].weather[0].icon +
          ".png";
        icon1.setAttribute("src", iconUrl1);
        forecastDate1.append(icon1);

        forecastDate2.textContent = `${outputDateStr2} 
        Min ${weather.list[8].main.temp_min} F 
        Max: ${weather.list[8].main.temp_max} F 
        Humidity:  ${weather.list[8].main.humidity}% 
        Weather conditions: ${weather.list[8].weather[0].description}`;
        var icon2 = document.createElement("img");
        var iconUrl2 =
          "http://openweathermap.org/img/w/" +
          weather.list[8].weather[0].icon +
          ".png";
        icon2.setAttribute("src", iconUrl2);
        forecastDate2.append(icon2);

        forecastDate3.textContent = `${outputDateStr3} 
        Min ${weather.list[16].main.temp_min} F 
        Max: ${weather.list[16].main.temp_max} F 
        Humidity:  ${weather.list[16].main.humidity}% 
        Weather conditions: ${weather.list[16].weather[0].description}`;
        var icon3 = document.createElement("img");
        var iconUrl3 =
          "http://openweathermap.org/img/w/" +
          weather.list[16].weather[0].icon +
          ".png";
        icon3.setAttribute("src", iconUrl3);
        forecastDate3.append(icon3);

        forecastDate4.textContent = `${outputDateStr4} 
        Min ${weather.list[24].main.temp_min} F 
        Max: ${weather.list[24].main.temp_max} F 
        Humidity:  ${weather.list[24].main.humidity}% 
        Weather conditions: ${weather.list[24].weather[0].description}`;
        var icon4 = document.createElement("img");
        var iconUrl4 =
          "http://openweathermap.org/img/w/" +
          weather.list[24].weather[0].icon +
          ".png";
        icon4.setAttribute("src", iconUrl4);
        forecastDate4.append(icon4);

        forecastDate5.textContent = `${outputDateStr5} 
        Min ${weather.list[32].main.temp_min} F 
        Max: ${weather.list[32].main.temp_max} F 
        Humidity:  ${weather.list[32].main.humidity}% 
        Weather conditions: ${weather.list[32].weather[0].description}`;
        var icon5 = document.createElement("img");
        var iconUrl5 =
          "http://openweathermap.org/img/w/" +
          weather.list[32].weather[0].icon +
          ".png";
        icon5.setAttribute("src", iconUrl5);
        forecastDate5.append(icon5);

        resultContainer.append(forecastDate1);
        resultContainer.append(forecastDate2);
        resultContainer.append(forecastDate3);
        resultContainer.append(forecastDate4);
        resultContainer.append(forecastDate5);
      }
    </script>
  </body>
</html>

API返回数据说明:返回的list数组包含40条3小时间隔的数据,每条数据包含dt(时间戳)、main(气温、湿度等)、weather(天气状况及图标)等字段。

解决方案

问题1:处理每日最高/最低气温,优化渲染逻辑

实现思路

先将API返回的3小时数据按日期分组,再对每组数据计算当日最高温、最低温,选取当日代表性时段(如中午)的天气图标和描述,最后动态生成DOM元素,避免重复代码。

代码替换

将原有的displayWeather函数替换为以下代码:

function displayWeather(weather) {
  const resultContainer = document.querySelector("#output");
  resultContainer.innerHTML = ""; // 清空历史结果

  // 1. 按日期分组数据
  const dailyGroups = {};
  weather.list.forEach(item => {
    const date = new Date(item.dt * 1000);
    // 生成YYYY-MM-DD格式的日期作为分组键
    const dateKey = `${date.getFullYear()}-${String(date.getMonth()+1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
    
    if (!dailyGroups[dateKey]) {
      dailyGroups[dateKey] = [];
    }
    dailyGroups[dateKey].push(item);
  });

  // 2. 生成城市标题
  const cityName = document.createElement("h2");
  cityName.textContent = weather.city.name;
  resultContainer.append(cityName);

  // 3. 遍历分组,处理每日数据
  Object.values(dailyGroups).slice(0,5).forEach(dayData => { // 取前5天数据
    // 计算当日最高/最低温
    const temps = dayData.map(item => item.main.temp);
    const maxTemp = Math.max(...temps);
    const minTemp = Math.min(...temps);
    // 取当天第5条数据(对应12点左右)作为天气状况展示,若不存在则取第一条
    const representativeItem = dayData[4] || dayData[0];
    const humidity = representativeItem.main.humidity;
    const weatherDesc = representativeItem.weather[0].description;
    const iconCode = representativeItem.weather[0].icon;

    // 格式化日期
    const date = new Date(dayData[0].dt * 1000);
    const dateStr = `${String(date.getMonth()+1).padStart(2, "0")}/${String(date.getDate()).padStart(2, "0")}/${date.getFullYear()}`;

    // 创建DOM元素
    const forecastItem = document.createElement("p");
    forecastItem.innerHTML = `${dateStr} 
    Min ${minTemp.toFixed(1)} F 
    Max: ${maxTemp.toFixed(1)} F 
    Humidity: ${humidity}% 
    Weather conditions: ${weatherDesc}`;
    
    const icon = document.createElement("img");
    icon.src = `http://openweathermap.org/img/w/${iconCode}.png`;
    forecastItem.append(icon);

    resultContainer.append(forecastItem);
  });
}

问题2:限制搜索范围为美国城市

实现思路

OpenWeatherMap的forecastAPI支持country参数,指定国家代码为US即可限制搜索范围;同时在API返回后校验城市所属国家,做双重保障。

代码修改

  1. 修改getWeather函数的API请求URL,添加&country=US参数:
function getWeather(query) {
  // 添加country=US参数限制美国城市
  var url =
    "http://api.openweathermap.org/data/2.5/forecast?q=" +
    query +
    "&country=US&units=imperial&APPID=56866f8407bb1e2d63330f3c046f35af";
  fetch(url)
    .then((response) => response.json())
    .then((data) => {
      // 额外校验:若返回城市的国家代码不是US,提示用户
      if (data.city && data.city.country !== "US") {
        const resultContainer = document.querySelector("#output");
        resultContainer.innerHTML = "<p>请输入美国境内的城市名称</p>";
        return;
      }
      displayWeather(data);
    })
    .catch(err => {
      const resultContainer = document.querySelector("#output");
      resultContainer.innerHTML = "<p>无法获取天气数据,请检查城市名称是否正确</p>";
    });
}
  1. 可选优化:修改表单提示,引导用户输入美国城市,比如将label改为:
<label for="city">Enter US City Name:</label>

内容的提问来源于stack exchange,提问作者user19334054

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:17:03