天气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
相关产品推荐
相关产品推荐

