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

如何使用JavaScript localStorage为天气应用实现搜索保存功能

问题排查

你现有代码存在5个直接导致功能失效的问题:

  • DOM选择器不匹配:JS中获取id="searcher"的搜索框,但HTML里搜索框没有加对应id,取到的元素是null
  • 事件监听无效:绑定的history不是浏览器原生事件,点击按钮无法触发存历史的逻辑
  • localStorage键名不一致:存储历史时用的键是historyList,删除历史时错写成histories,会导致删除操作后数据错乱
  • 历史条目无交互:没有给历史项绑定点击查天气、触发删除的事件,功能无法实际使用
  • 初始化无兼容判断:读取本地历史时没做空值校验,首次打开页面无历史记录时会直接报错
  • 无自动存历史逻辑:搜索成功后不会自动写入记录,也没做重复城市去重、历史条数限制
完整修正方案

修正后的HTML代码

补全缺失的元素id,修正原有笔误:

<html>
   <body>
      <div class="card" id="search-card">
         <div class="search">
            <!-- 补全搜索框id,和JS选择器对应 -->
            <input type="text" name="searchbox" id="searcher" class="search-bar" placeholder="Search...">
            <button id="searchBtn">🔍</button>
         </div>
         <div class="weather">
            <h2 class="city">Weather in Accra</h2>
            <div class="temp">
               <h1>21°C</h1>
            </div>
            <div class="flex">
               <img src="" alt="" class="icon">
               <div class="description">Cloudy</div>
            </div>
            <div class="humidity">Humid: 53% </div>
            <div class="wind"> Wind Speed: 6.2 km/h</div>
         </div>
         <h4>搜索历史</h4>
         <ul id="historyList"></ul>
      </div>
   </body>
</html>

修正后的JavaScript代码

统一逻辑、补全交互、修复存储问题:

let weather = {
    apiKey: "", // 填入你自己的OpenWeatherMap接口密钥即可正常请求
    fetchWeather: function(city) {
        fetch("https://api.openweathermap.org/data/2.5/weather?q="+ city + "&units=metric&appid="+ this.apiKey)
        .then((response) => {
            if(!response.ok) throw new Error("城市不存在或请求失败");
            return response.json();
        })
        .then((data)=> {
            this.displayWeather(data);
            // 搜索成功后自动存入历史
            this.saveToHistory(city.trim());
        })
        .catch(err => alert(err.message));   
    },
    displayWeather: function(data){
        const  {name} = data;
        const {icon, description} = data.weather[0];
        const {temp, humidity} =data.main;
        const {speed} = data.wind;
        document.querySelector(".city").innerText = "Weather in " + name;
        document.querySelector(".icon").src = "http://openweathermap.org/img/wn/"+ icon + ".png";
        document.querySelector(".description").innerText = description;
        document.querySelector(".temp").innerText = temp+ "°C" ;
        document.querySelector(".humidity").innerText = "Humidity " + humidity + "%";
        document.querySelector(".wind").innerText =  "Wind Speed " + speed + "km/h";
    },
    search:function(){
        const cityVal = document.querySelector(".search-bar").value.trim();
        if(!cityVal) return;
        this.fetchWeather(cityVal);
    },
    // 统一存储历史方法,做去重、条数限制
    saveToHistory: function(city) {
        // 先移除已存在的同名城市,避免重复
        saved = saved.filter(item => item.toLowerCase() !== city.toLowerCase());
        // 最新搜索的记录放在最顶部
        saved.unshift(city);
        // 最多保留10条历史,超出则删除最早的记录
        if(saved.length > 10) saved.pop();
        // 统一使用historyList作为键名存储
        localStorage.setItem("historyList", JSON.stringify(saved));
        // 重新渲染历史列表
        renderHistoryList();
    }
} 

// 绑定搜索触发事件
document.querySelector("#searchBtn").addEventListener("click", () => weather.search());
document.querySelector(".search-bar").addEventListener("keydown", (e) => {
    if(e.key === "Enter") weather.search();
})

// 历史功能相关DOM
const historyList = document.getElementById("historyList");
const searcher = document.getElementById("searcher");
// 初始化读取本地存储,做空值兼容
let saved = localStorage.getItem("historyList") ? JSON.parse(localStorage.getItem("historyList")) : [];

// 统一渲染历史列表,避免重复代码
const renderHistoryList = () => {
    historyList.innerHTML = "";
    saved.forEach((cityName) => {
        const li = document.createElement("li");
        li.style.cssText = "display:flex;justify-content:space-between;align-items:center;margin:8px 0;padding:6px 10px;border-radius:4px;cursor:pointer;background:#f0f0f0;";
        // 城市名点击直接查询对应天气
        const cityText = document.createElement("span");
        cityText.innerText = cityName;
        cityText.addEventListener("click", () => {
            searcher.value = cityName;
            weather.search();
        })
        // 单条删除按钮
        const delBtn = document.createElement("button");
        delBtn.innerText = "×";
        delBtn.style.cssText = "border:none;background:transparent;cursor:pointer;font-size:18px;";
        delBtn.addEventListener("click", (e) => {
            e.stopPropagation(); // 避免点击删除时触发城市查询
            deleteHistory(delBtn);
        })
        li.append(cityText, delBtn);
        historyList.appendChild(li);
    })
}

// 修正删除逻辑的键名错误
const deleteHistory = (btn) => {
    const el = btn.parentNode;
    const index = [...el.parentElement.children].indexOf(el);
    saved.splice(index, 1);
    localStorage.setItem("historyList", JSON.stringify(saved));
    renderHistoryList();
};

// 页面加载完成后自动渲染已有历史记录
window.addEventListener("load", renderHistoryList);

实现效果

  • 搜索城市成功后自动保存记录,相同城市自动去重,最多保留10条最近搜索,最新记录置顶
  • 点击历史条目里的城市名,直接触发该城市的天气查询
  • 每条历史附带删除按钮,可单独删除对应记录,刷新页面数据不丢失
  • 支持回车键触发搜索,空输入不会发起无效请求
  • 所有本地存储操作统一使用historyList作为键名,不会出现数据不匹配问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 22:33:22