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

天气App开发报错:Cannot read properties of null (reading 'addEventListener')

天气App报错排查:Cannot read properties of null (reading 'addEventListener')

问题描述

开发天气App时触发报错:Cannot read properties of null (reading 'addEventListener'),相关代码如下:

JavaScript代码

let apiUrl = "https://api.openweathermap.org/data/2.5/weather?units=metric&q=";
let searchBox = document.querySelector(".search input");
let searchBtn = document.querySelector(".search button");

async function FetchWeatherDataByCityName(city) {
  const response = await fetch(apiUrl + city + `&appid=${apiKey}`);
  var data = await response.json();
  console.log(data);

  document.querySelector(".city-heading").innerHTML = data.name;
  document.querySelector(".temp-heading").innerHTML =
    Math.round(data.main.temp) + "°C";
  document.querySelector(".weather-icon").innerHTML = data.weather[0].main;
  document.querySelector(".h3-humidity-heading").innerHTML =
    data.main.humidity + "%";
  document.querySelector(".h3-wind-speed").innerHTML =
    data.wind.speed + " Km/h";

  // 选择天气图标
  if (data.weather[0].main == "Clouds") {
    document.querySelector(".weather-icon").src = "images/clouds.png";
  } else if (data.weather[0].main == "Clear") {
    document.querySelector(".weather-icon").src = "images/clear.png";
  } else if (data.weather[0].main == "Drizzle") {
    document.querySelector(".weather-icon").src = "images/drizzle.png";
  } else if (data.weather[0].main == "Mist") {
    document.querySelector(".weather-icon").src = "images/mist.png";
  } else if (data.weather[0].main == "Rain") {
    document.querySelector(".weather-icon").src = "images/rain.png";
  } else if (data.weather[0].main == "Snow") {
    document.querySelector(".weather-icon").src = "images/snow.png";
  }
}

searchBtn.addEventListener("click", () => {
  FetchWeatherDataByCityName(searchBox.value);
});

HTML代码

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Weather App</title>
    <link rel="stylesheet" href="./styles.css" />
    <script src="./index.js"></script>
  </head>
  <body class="body-styles">
    <div class="weather-app-card">
      <div class="input-and-search-icon-styling">
        <div class="search">
          <input
            class="search-input"
            type="text"
            placeholder="Enter City Name"
          />
        </div>
        <div class="search">
          <button class="search-icon-btn">
            <img class="search-icon" src="./images/search.png" alt="" />
          </button>
        </div>
      </div>
      <div class="">
        <img class="weather-icon" src="./images/clear.png" alt="" />
      </div>
      <div>
        <h1 class="temp-heading">7°C</h1>
        <h2 class="city-heading">New York</h2>
      </div>
      <div class="humidity-and-wind-speed">
        <div class="humidity-icon-and-text">
          <div>
            <img class="humidity-image" src="./images/humidity.png" alt="" />
          </div>
          <div class="humidity-percentage">
            <h3 class="h3-humidity-heading">48%</h3>
            <h4 class="h4-humidity">Humidity</h4>
          </div>
        </div>
        <div class="wind-speed-icon-and-text">
          <div>
            <img class="wind-image" src="./images/wind.png" alt="" />
          </div>
          <div>
            <h3 class="h3-wind-speed">10.29Km/h</h3>
            <h4 class="h4-wind-speed">wind speed</h4>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

报错原因

核心问题是JavaScript代码执行时机早于DOM元素加载完成:
你把<script>标签放在了<head>里,浏览器解析到此处时,<body>内的搜索按钮等DOM元素还未渲染,此时document.querySelector(".search button")返回null,调用null.addEventListener必然抛出报错。

解决方案

两种简单有效的修复方式:

方式1:将脚本移到标签末尾

把<script src="./index.js"></script>移动到</body>之前,确保DOM完全加载后再执行JS:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Weather App</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body class="body-styles">
    <!-- 所有DOM内容保持不变 -->
    <div class="weather-app-card">...</div>
    
    <!-- 脚本移到此处 -->
    <script src="./index.js"></script>
  </body>
</html>

方式2:用DOMContentLoaded事件包裹代码

若不想移动脚本位置,在JS外层包裹DOMContentLoaded事件监听,确保DOM加载完成后再执行逻辑:

document.addEventListener('DOMContentLoaded', function() {
  let apiUrl = "https://api.openweathermap.org/data/2.5/weather?units=metric&q=";
  let searchBox = document.querySelector(".search input");
  let searchBtn = document.querySelector(".search button");

  async function FetchWeatherDataByCityName(city) {
    // 原函数内容保持不变
  }

  searchBtn.addEventListener("click", () => {
    FetchWeatherDataByCityName(searchBox.value);
  });
});

额外优化建议

  • 添加元素存在性检查,避免类似报错:
    if (searchBtn && searchBox) {
      searchBtn.addEventListener("click", () => {
        FetchWeatherDataByCityName(searchBox.value);
      });
    }
    
  • 提前定义apiKey变量,否则请求OpenWeatherMap API会失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 08:44:55