
在上一篇文章中,我们学习了JavaScript的函数、对象和数组这些核心概念。现在,让我们继续深入学习JavaScript的高级特性:异步编程、DOM操作和事件处理。这些特性在现代Web开发中至关重要,掌握它们将帮助你创建更加动态和响应式的Web应用程序。
在2025年,随着Web应用程序变得越来越复杂,异步编程、DOM操作和事件处理的重要性也日益凸显。了解这些高级特性不仅可以帮助你更好地理解和使用现代JavaScript框架(如React、Vue和Angular),还能让你更有效地利用AI辅助工具来提升开发效率。本文将通过详细的讲解和丰富的示例,帮助你掌握这些重要概念,并通过实战练习巩固所学知识。
|要点|描述|\n|-|-|\n|痛点|异步编程概念抽象难以理解;DOM操作和事件处理容易出错;不知道如何在实际项目中应用这些高级特性|\n|方案|通过详细的讲解、丰富的示例和实战练习,帮助你深入理解这些高级概念|\n|驱动|掌握这些高级特性是成为前端开发工程师的关键,也是利用AI提升开发效率的基础|\n
|章节|内容|\n|-|-|\n|1|JavaScript异步编程详解|\n|2|DOM操作与文档遍历|\n|3|JavaScript事件处理|\n|4|使用AI助手优化异步编程、DOM操作和事件处理|\n|5|实战练习:构建一个动态天气应用|\n
JavaScript是单线程语言,但为了处理耗时操作(如网络请求、文件读写等),JavaScript提供了异步编程的能力。在本节中,我们将深入学习JavaScript异步编程的各种方式。
回调函数是JavaScript中最基本的异步编程方式,它允许我们将一个函数作为参数传递给另一个函数,当异步操作完成时,这个函数会被调用。
// 模拟异步操作
function fetchData(callback) {
setTimeout(function() {
const data = { name: '张三', age: 30 };
callback(null, data); // 第一个参数通常用于传递错误信息
}, 1000);
}
// 使用回调函数处理异步结果
fetchData(function(error, data) {
if (error) {
console.error('发生错误:', error);
return;
}
console.log('获取到的数据:', data); // 输出:获取到的数据: { name: '张三', age: 30 }
});回调函数的嵌套使用可能会导致"回调地狱"(Callback Hell),使代码难以阅读和维护:
fetchUserData(userId, function(error, userData) {
if (error) {
console.error('获取用户数据失败:', error);
return;
}
fetchUserPosts(userData.id, function(error, posts) {
if (error) {
console.error('获取用户帖子失败:', error);
return;
}
fetchPostComments(posts[0].id, function(error, comments) {
if (error) {
console.error('获取评论失败:', error);
return;
}
// 处理数据...
});
});
});ES6引入的Promise是一种更优雅的处理异步操作的方式,它避免了回调地狱的问题。
// 创建Promise
function fetchData() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
const data = { name: '张三', age: 30 };
resolve(data); // 操作成功时调用
// 发生错误时可以调用 reject(new Error('错误信息'));
}, 1000);
});
}
// 使用Promise处理异步结果
fetchData()
.then(function(data) {
console.log('获取到的数据:', data); // 输出:获取到的数据: { name: '张三', age: 30 }
return data.name; // 可以在then方法中返回值,供下一个then方法使用
})
.then(function(name) {
console.log('用户名:', name); // 输出:用户名: 张三
})
.catch(function(error) {
console.error('发生错误:', error); // 捕获任何Promise链中的错误
});Promise的链式调用使异步代码更加清晰易读:
fetchUserData(userId)
.then(function(userData) {
return fetchUserPosts(userData.id);
})
.then(function(posts) {
return fetchPostComments(posts[0].id);
})
.then(function(comments) {
// 处理数据...
})
.catch(function(error) {
console.error('发生错误:', error);
});Promise提供了一些静态方法,用于处理多个Promise:
// Promise.all:等待所有Promise都完成
const promise1 = fetchData1();
const promise2 = fetchData2();
const promise3 = fetchData3();
Promise.all([promise1, promise2, promise3])
.then(function(results) {
const [result1, result2, result3] = results;
// 处理所有结果...
})
.catch(function(error) {
console.error('发生错误:', error);
});
// Promise.race:等待第一个完成的Promise
Promise.race([promise1, promise2, promise3])
.then(function(firstResult) {
// 处理第一个完成的结果...
})
.catch(function(error) {
console.error('发生错误:', error);
});ES2017引入的async/await语法糖使异步代码看起来更像同步代码,进一步提高了代码的可读性。
// 使用async关键字定义异步函数
async function getData() {
try {
// 使用await关键字等待Promise完成
const data = await fetchData();
console.log('获取到的数据:', data); // 输出:获取到的数据: { name: '张三', age: 30 }
// 异步函数中的其他操作
const name = data.name;
console.log('用户名:', name); // 输出:用户名: 张三
return name;
} catch (error) {
console.error('发生错误:', error); // 捕获异步操作中的错误
throw error; // 可以选择重新抛出错误
}
}
// 调用异步函数
getData()
.then(function(name) {
console.log('异步函数返回的结果:', name); // 输出:异步函数返回的结果: 张三
})
.catch(function(error) {
console.error('捕获到错误:', error);
});async/await语法使复杂的异步代码更加简洁易读:
async function processUserData(userId) {
try {
const userData = await fetchUserData(userId);
const posts = await fetchUserPosts(userData.id);
const comments = await fetchPostComments(posts[0].id);
// 处理数据...
return { userData, posts, comments };
} catch (error) {
console.error('处理用户数据时发生错误:', error);
throw error;
}
}DOM(Document Object Model,文档对象模型)是HTML和XML文档的编程接口。JavaScript通过DOM可以操作网页上的元素,使网页具有动态交互性。在本节中,我们将学习如何使用JavaScript操作DOM。
JavaScript提供了多种方式来选择DOM元素:
// 通过ID选择元素
const elementById = document.getElementById('myElement');
// 通过类名选择元素
const elementsByClass = document.getElementsByClassName('myClass'); // 返回HTMLCollection
// 通过标签名选择元素
const elementsByTag = document.getElementsByTagName('div'); // 返回HTMLCollection
// 通过CSS选择器选择元素
const elementBySelector = document.querySelector('.myClass > p'); // 返回第一个匹配的元素
const elementsBySelectorAll = document.querySelectorAll('div.myClass'); // 返回NodeList我们可以修改DOM元素的内容、属性和样式:
// 修改元素内容
const element = document.getElementById('myElement');
element.textContent = '新的文本内容'; // 修改文本内容
// 或者使用innerHTML(注意安全问题,可能导致XSS攻击)
element.innerHTML = '<strong>加粗的文本</strong>';
// 修改元素属性
const link = document.querySelector('a');
link.href = 'https://www.example.com';
link.title = '示例网站';
link.setAttribute('target', '_blank'); // 设置属性
link.removeAttribute('class'); // 删除属性
// 修改元素样式
const div = document.querySelector('div');
div.style.backgroundColor = 'blue';
div.style.color = 'white';
div.style.padding = '10px';
div.style.marginTop = '20px';
div.style.display = 'none'; // 隐藏元素
// 添加或删除CSS类
const element = document.querySelector('.myElement');
element.classList.add('newClass'); // 添加类
if (element.classList.contains('oldClass')) {
element.classList.remove('oldClass'); // 删除类
}
element.classList.toggle('active'); // 切换类(存在则删除,不存在则添加)我们可以创建新的DOM元素并将其插入到文档中:
// 创建新元素
const newDiv = document.createElement('div');
newDiv.textContent = '新创建的div';
newDiv.className = 'new-div';
// 将元素添加到文档中
const container = document.getElementById('container');
container.appendChild(newDiv); // 添加到容器末尾
// 在指定位置插入元素
const referenceElement = document.getElementById('reference');
container.insertBefore(newDiv, referenceElement); // 插入到reference元素之前
// 创建文本节点
const textNode = document.createTextNode('文本内容');
container.appendChild(textNode);
// 克隆元素
const clonedElement = newDiv.cloneNode(true); // true表示深克隆(克隆子元素)
container.appendChild(clonedElement);我们可以删除或替换DOM元素:
// 删除元素
const elementToRemove = document.getElementById('removeMe');
elementToRemove.parentNode.removeChild(elementToRemove);
// 替换元素
const oldElement = document.getElementById('oldElement');
const newElement = document.createElement('div');
newElement.textContent = '新元素';
oldElement.parentNode.replaceChild(newElement, oldElement);事件是用户与网页交互时产生的动作,如点击、键盘输入、鼠标移动等。JavaScript可以捕获和处理这些事件,使网页能够响应用户的交互。在本节中,我们将学习JavaScript的事件处理机制。
我们可以使用事件监听器来捕获和处理事件:
// 添加事件监听器
const button = document.getElementById('myButton');
button.addEventListener('click', function(event) {
console.log('按钮被点击了!');
console.log('事件对象:', event);
});
// 使用命名函数作为事件处理程序
function handleClick(event) {
console.log('按钮被点击了!');
console.log('事件目标:', event.target); // 触发事件的元素
console.log('当前元素:', event.currentTarget); // 当前处理事件的元素
event.preventDefault(); // 阻止默认行为
event.stopPropagation(); // 阻止事件冒泡
}
button.addEventListener('click', handleClick);
// 移除事件监听器
button.removeEventListener('click', handleClick);JavaScript支持多种事件类型,以下是一些常见的事件:
// 鼠标事件
const element = document.getElementById('myElement');
element.addEventListener('click', function() { console.log('点击'); });
element.addEventListener('dblclick', function() { console.log('双击'); });
element.addEventListener('mousedown', function() { console.log('鼠标按下'); });
element.addEventListener('mouseup', function() { console.log('鼠标释放'); });
element.addEventListener('mouseenter', function() { console.log('鼠标进入'); });
element.addEventListener('mouseleave', function() { console.log('鼠标离开'); });
element.addEventListener('mousemove', function() { console.log('鼠标移动'); });
// 键盘事件
const input = document.getElementById('myInput');
input.addEventListener('keydown', function(event) { console.log('按下按键:', event.key); });
input.addEventListener('keyup', function(event) { console.log('释放按键:', event.key); });
input.addEventListener('keypress', function(event) { console.log('按键按下并释放:', event.key); });
// 表单事件
const form = document.getElementById('myForm');
form.addEventListener('submit', function(event) {
console.log('表单提交');
event.preventDefault(); // 阻止表单默认提交行为
});
input.addEventListener('change', function() { console.log('值改变'); });
input.addEventListener('input', function() { console.log('输入内容'); });
input.addEventListener('focus', function() { console.log('获取焦点'); });
input.addEventListener('blur', function() { console.log('失去焦点'); });
// 窗口事件
window.addEventListener('load', function() { console.log('页面加载完成'); });
window.addEventListener('resize', function() { console.log('窗口大小改变'); });
window.addEventListener('scroll', function() { console.log('页面滚动'); });事件流描述了事件从页面中传播的顺序。DOM事件流包含三个阶段:捕获阶段、目标阶段和冒泡阶段。
// HTML结构:<div id="outer"><div id="middle"><div id="inner">点击我</div></div></div>
const outer = document.getElementById('outer');
const middle = document.getElementById('middle');
const inner = document.getElementById('inner');
// 捕获阶段处理事件(第三个参数为true)
outer.addEventListener('click', function() { console.log('outer捕获'); }, true);
middle.addEventListener('click', function() { console.log('middle捕获'); }, true);
inner.addEventListener('click', function() { console.log('inner捕获'); }, true);
// 冒泡阶段处理事件(第三个参数为false或省略)
outer.addEventListener('click', function() { console.log('outer冒泡'); });
middle.addEventListener('click', function() { console.log('middle冒泡'); });
inner.addEventListener('click', function() { console.log('inner冒泡'); });
// 点击inner元素时,输出顺序为:
// outer捕获 -> middle捕获 -> inner捕获 -> inner冒泡 -> middle冒泡 -> outer冒泡在2025年,AI技术已经成为编程的强大助手。下面介绍几种利用AI工具优化JavaScript异步编程、DOM操作和事件处理的方法。
AI代码优化器可以分析你的JavaScript代码,并提供优化建议,使你的异步编程、DOM操作和事件处理代码更加高效、简洁和易读。
例如,假设你有以下异步代码:
function fetchUserData(userId) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve({ id: userId, name: '张三', age: 30 });
}, 1000);
});
}
function fetchUserPosts(userId) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve([{ id: 1, title: '文章1' }, { id: 2, title: '文章2' }]);
}, 1000);
});
}
function fetchComments(postId) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve([{ id: 1, content: '评论1' }, { id: 2, content: '评论2' }]);
}, 1000);
});
}
function processData() {
const userId = 1;
fetchUserData(userId)
.then(function(userData) {
return fetchUserPosts(userId);
})
.then(function(posts) {
return fetchComments(posts[0].id);
})
.then(function(comments) {
console.log('处理完成', comments);
})
.catch(function(error) {
console.error('发生错误:', error);
});
}AI代码优化器可能会建议你使用async/await语法来优化这段代码,使它更加清晰易读:
async function processData() {
try {
const userId = 1;
const userData = await fetchUserData(userId);
const posts = await fetchUserPosts(userId);
const comments = await fetchComments(posts[0].id);
console.log('处理完成', comments);
} catch (error) {
console.error('发生错误:', error);
}
}AI代码生成器可以根据你的需求生成JavaScript异步编程、DOM操作和事件处理的代码片段,帮助你快速实现功能。
例如,你可以告诉AI:“帮我生成一个JavaScript函数,用于延迟加载图片”,AI会生成相应的代码:
function lazyLoadImages() {
const images = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
observer.unobserve(img);
}
});
});
images.forEach(img => {
imageObserver.observe(img);
});
}
// 页面加载完成后执行
window.addEventListener('load', lazyLoadImages);AI错误检测器可以帮助你找出JavaScript异步编程、DOM操作和事件处理中的潜在问题和错误,并提供修复建议。
例如,假设你有以下代码:
// 错误的异步代码
function fetchData() {
setTimeout(function() {
const data = { name: '张三', age: 30 };
return data; // 错误:在setTimeout回调中返回值没有意义
}, 1000);
}
const result = fetchData();
console.log(result); // 输出:undefinedAI错误检测器可以识别这个问题,并建议你使用Promise或回调函数来正确处理异步操作:
// 正确的异步代码(使用Promise)
function fetchData() {
return new Promise(function(resolve) {
setTimeout(function() {
const data = { name: '张三', age: 30 };
resolve(data);
}, 1000);
});
}
fetchData().then(function(result) {
console.log(result); // 输出:{ name: '张三', age: 30 }
});现在,让我们通过一个实际的项目来巩固所学的JavaScript异步编程、DOM操作和事件处理的知识。我们将构建一个动态天气应用,该应用可以显示用户所在位置的天气信息,并允许用户查询其他城市的天气。
我们将创建一个动态天气应用,该应用可以:
weather-app的文件夹index.html、style.css和app.js文件index.html中添加以下内容:<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动态天气应用</title>
<link rel="stylesheet" href="style.css">
<script src="app.js" defer></script>
</head>
<body>
<div class="container">
<header>
<h1>动态天气应用</h1>
<div class="search-container">
<input type="text" id="cityInput" placeholder="输入城市名称...">
<button id="searchBtn">搜索</button>
</div>
</header>
<main>
<div id="current-weather" class="weather-card">
<div class="loading">加载中...</div>
<div class="weather-info hidden">
<h2 id="city-name"></h2>
<div class="weather-main">
<div class="temperature">
<span id="current-temp"></span>
<span class="unit">°C</span>
</div>
<div class="weather-icon">
<img id="weather-icon" src="" alt="天气图标">
</div>
</div>
<p id="weather-description"></p>
<div class="weather-details">
<div class="detail-item">
<span class="detail-label">湿度:</span>
<span id="humidity"></span>
</div>
<div class="detail-item">
<span class="detail-label">风速:</span>
<span id="wind-speed"></span>
</div>
<div class="detail-item">
<span class="detail-label">气压:</span>
<span id="pressure"></span>
</div>
</div>
</div>
</div>
<div id="forecast" class="forecast-container">
<h3>未来天气预报</h3>
<div id="forecast-list" class="forecast-list">
<!-- 天气预报项将通过JavaScript动态添加 -->
</div>
</div>
</main>
<footer>
<p>© 2025 动态天气应用 | 使用OpenWeatherMap API</p>
</footer>
</div>
</body>
</html>style.css中添加以下内容:* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background-color: #f5f5f5;
color: #333;
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 30px;
}
h1 {
color: #2c3e50;
margin-bottom: 20px;
}
.search-container {
display: flex;
justify-content: center;
max-width: 500px;
margin: 0 auto;
}
#cityInput {
flex: 1;
padding: 12px;
font-size: 16px;
border: 2px solid #ddd;
border-radius: 4px 0 0 4px;
outline: none;
}
#searchBtn {
padding: 12px 20px;
font-size: 16px;
background-color: #3498db;
color: white;
border: none;
border-radius: 0 4px 4px 0;
cursor: pointer;
transition: background-color 0.3s ease;
}
#searchBtn:hover {
background-color: #2980b9;
}
main {
display: flex;
flex-direction: column;
gap: 30px;
}
.weather-card {
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 30px;
text-align: center;
position: relative;
overflow: hidden;
}
.loading {
font-size: 18px;
color: #666;
padding: 20px;
}
.hidden {
display: none;
}
#city-name {
font-size: 28px;
margin-bottom: 20px;
color: #2c3e50;
}
.weather-main {
display: flex;
align-items: center;
justify-content: center;
gap: 30px;
margin-bottom: 20px;
}
.temperature {
font-size: 64px;
font-weight: bold;
color: #e74c3c;
}
.unit {
font-size: 32px;
font-weight: normal;
color: #34495e;
}
.weather-icon img {
width: 120px;
height: 120px;
}
#weather-description {
font-size: 20px;
color: #7f8c8d;
margin-bottom: 30px;
text-transform: capitalize;
}
.weather-details {
display: flex;
justify-content: center;
gap: 40px;
flex-wrap: wrap;
}
.detail-item {
text-align: center;
}
.detail-label {
display: block;
font-size: 14px;
color: #95a5a6;
margin-bottom: 5px;
}
.detail-item span:not(.detail-label) {
font-size: 18px;
color: #2c3e50;
font-weight: bold;
}
.forecast-container {
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 30px;
}
.forecast-container h3 {
text-align: center;
margin-bottom: 20px;
color: #2c3e50;
}
.forecast-list {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 20px;
}
.forecast-item {
flex: 1;
min-width: 150px;
background-color: #f8f9fa;
padding: 20px;
border-radius: 8px;
text-align: center;
}
.forecast-date {
font-weight: bold;
margin-bottom: 10px;
color: #2c3e50;
}
.forecast-temp {
font-size: 18px;
color: #e74c3c;
margin-bottom: 10px;
}
.forecast-icon img {
width: 60px;
height: 60px;
margin-bottom: 10px;
}
.forecast-desc {
font-size: 14px;
color: #7f8c8d;
text-transform: capitalize;
}
footer {
text-align: center;
margin-top: 50px;
color: #7f8c8d;
font-size: 14px;
}
/* 根据天气状况设置不同的背景 */
body.clear {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}
body.clouds {
background: linear-gradient(135deg, #d7d2cc 0%, #304352 100%);
}
body.rain {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
body.snow {
background: linear-gradient(135deg, #e0c3fc 0%, #8ec5fc 100%);
}
@media (max-width: 768px) {
.weather-main {
flex-direction: column;
gap: 20px;
}
.temperature {
font-size: 48px;
}
.unit {
font-size: 24px;
}
.weather-icon img {
width: 100px;
height: 100px;
}
.weather-details {
gap: 20px;
}
.forecast-list {
justify-content: center;
}
}app.js中添加以下内容:// API密钥(注意:在实际项目中,不要将API密钥直接硬编码在前端代码中)
const API_KEY = 'YOUR_API_KEY'; // 替换为你自己的OpenWeatherMap API密钥
const BASE_URL = 'https://api.openweathermap.org/data/2.5';
// 等待DOM加载完成
document.addEventListener('DOMContentLoaded', function() {
// 获取DOM元素
const cityInput = document.getElementById('cityInput');
const searchBtn = document.getElementById('searchBtn');
const currentWeatherContainer = document.getElementById('current-weather');
const loadingIndicator = currentWeatherContainer.querySelector('.loading');
const weatherInfo = currentWeatherContainer.querySelector('.weather-info');
const cityNameElement = document.getElementById('city-name');
const currentTempElement = document.getElementById('current-temp');
const weatherIconElement = document.getElementById('weather-icon');
const weatherDescriptionElement = document.getElementById('weather-description');
const humidityElement = document.getElementById('humidity');
const windSpeedElement = document.getElementById('wind-speed');
const pressureElement = document.getElementById('pressure');
const forecastListElement = document.getElementById('forecast-list');
// 搜索按钮点击事件
searchBtn.addEventListener('click', function() {
const city = cityInput.value.trim();
if (city) {
getWeatherByCity(city);
} else {
alert('请输入城市名称');
}
});
// 按Enter键搜索
cityInput.addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
searchBtn.click();
}
});
// 尝试获取用户位置
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
function(position) {
const { latitude, longitude } = position.coords;
getWeatherByCoords(latitude, longitude);
},
function(error) {
console.error('获取位置失败:', error);
// 默认显示北京的天气
getWeatherByCity('北京');
alert('无法获取您的位置信息,将显示北京的天气。您可以在搜索框中输入其他城市名称。');
}
);
} else {
console.error('浏览器不支持地理定位');
// 默认显示北京的天气
getWeatherByCity('北京');
alert('您的浏览器不支持地理定位,将显示北京的天气。您可以在搜索框中输入其他城市名称。');
}
// 根据经纬度获取天气信息
async function getWeatherByCoords(latitude, longitude) {
try {
showLoading();
// 并行请求当前天气和天气预报
const [currentWeatherResponse, forecastResponse] = await Promise.all([
fetch(`${BASE_URL}/weather?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric&lang=zh_cn`),
fetch(`${BASE_URL}/forecast?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric&lang=zh_cn`)
]);
if (!currentWeatherResponse.ok || !forecastResponse.ok) {
throw new Error('获取天气数据失败');
}
const currentWeatherData = await currentWeatherResponse.json();
const forecastData = await forecastResponse.json();
displayCurrentWeather(currentWeatherData);
displayForecast(forecastData);
} catch (error) {
console.error('获取天气数据时发生错误:', error);
showError('获取天气数据失败,请稍后再试');
}
}
// 根据城市名称获取天气信息
async function getWeatherByCity(city) {
try {
showLoading();
// 并行请求当前天气和天气预报
const [currentWeatherResponse, forecastResponse] = await Promise.all([
fetch(`${BASE_URL}/weather?q=${city}&appid=${API_KEY}&units=metric&lang=zh_cn`),
fetch(`${BASE_URL}/forecast?q=${city}&appid=${API_KEY}&units=metric&lang=zh_cn`)
]);
if (!currentWeatherResponse.ok || !forecastResponse.ok) {
throw new Error('获取天气数据失败');
}
const currentWeatherData = await currentWeatherResponse.json();
const forecastData = await forecastResponse.json();
displayCurrentWeather(currentWeatherData);
displayForecast(forecastData);
} catch (error) {
console.error('获取天气数据时发生错误:', error);
showError('未找到该城市的天气数据,请检查城市名称是否正确');
}
}
// 显示当前天气信息
function displayCurrentWeather(data) {
// 隐藏加载指示器,显示天气信息
hideLoading();
// 更新DOM元素
cityNameElement.textContent = `${data.name}, ${data.sys.country}`;
currentTempElement.textContent = Math.round(data.main.temp);
weatherIconElement.src = `http://openweathermap.org/img/wn/${data.weather[0].icon}@2x.png`;
weatherIconElement.alt = data.weather[0].description;
weatherDescriptionElement.textContent = data.weather[0].description;
humidityElement.textContent = `${data.main.humidity}%`;
windSpeedElement.textContent = `${data.wind.speed} m/s`;
pressureElement.textContent = `${data.main.pressure} hPa`;
// 根据天气状况设置背景
setWeatherBackground(data.weather[0].main);
}
// 显示天气预报
function displayForecast(data) {
// 清空之前的天气预报
forecastListElement.innerHTML = '';
// 只显示每天的一个预报(每8小时更新一次,所以取第0、8、16个等)
const dailyForecasts = data.list.filter((_, index) => index % 8 === 0);
dailyForecasts.forEach(forecast => {
const date = new Date(forecast.dt * 1000);
const dayName = date.toLocaleDateString('zh-CN', { weekday: 'short' });
const dateStr = date.toLocaleDateString('zh-CN');
const forecastItem = document.createElement('div');
forecastItem.className = 'forecast-item';
forecastItem.innerHTML = `
<div class="forecast-date">${dayName}<br>${dateStr}</div>
<div class="forecast-icon">
<img src="http://openweathermap.org/img/wn/${forecast.weather[0].icon}@2x.png" alt="${forecast.weather[0].description}">
</div>
<div class="forecast-temp">${Math.round(forecast.main.temp)}°C</div>
<div class="forecast-desc">${forecast.weather[0].description}</div>
`;
forecastListElement.appendChild(forecastItem);
});
}
// 根据天气状况设置背景
function setWeatherBackground(weatherMain) {
// 移除之前的天气类
document.body.classList.remove('clear', 'clouds', 'rain', 'snow');
// 根据天气类型添加相应的类
switch(weatherMain.toLowerCase()) {
case 'clear':
document.body.classList.add('clear');
break;
case 'clouds':
document.body.classList.add('clouds');
break;
case 'rain':
case 'drizzle':
document.body.classList.add('rain');
break;
case 'snow':
document.body.classList.add('snow');
break;
default:
document.body.classList.add('clear');
}
}
// 显示加载指示器
function showLoading() {
loadingIndicator.classList.remove('hidden');
weatherInfo.classList.add('hidden');
forecastListElement.innerHTML = '<div class="loading">加载中...</div>';
}
// 隐藏加载指示器
function hideLoading() {
loadingIndicator.classList.add('hidden');
weatherInfo.classList.remove('hidden');
}
// 显示错误信息
function showError(message) {
loadingIndicator.textContent = message;
weatherInfo.classList.add('hidden');
forecastListElement.innerHTML = `<div class="error">${message}</div>`;
}
});app.js文件中的YOUR_API_KEY。index.html文件。这个动态天气应用充分利用了JavaScript的异步编程、DOM操作和事件处理特性:
Promise.all和async/await来处理并发的API请求,提高了应用的性能。通过本文的学习,你已经掌握了JavaScript的高级特性:异步编程、DOM操作和事件处理。这些特性在现代Web开发中至关重要,掌握它们将帮助你创建更加动态和响应式的Web应用程序。
在2025年,随着Web应用程序变得越来越复杂,异步编程、DOM操作和事件处理的重要性也日益凸显。了解这些高级特性不仅可以帮助你更好地理解和使用现代JavaScript框架(如React、Vue和Angular),还能让你更有效地利用AI辅助工具来提升开发效率。
通过实战练习,你已经将所学的知识应用到实际项目中,这是学习编程的最佳方式。继续保持实践,你将很快成为一名熟练的前端开发工程师。
|要点|描述|\n|-|-|\n|价值|深入理解JavaScript异步编程、DOM操作和事件处理的高级特性,能够应用到实际项目中|\n|行动|继续学习现代JavaScript框架(如React、Vue和Angular),进一步提升前端开发技能|\n
|来源|描述|\n|-|-|\n|MDN Web Docs|JavaScript异步编程、DOM操作和事件处理的官方文档|\n|JavaScript.info|JavaScript高级教程与进阶指南|\n|W3Schools|JavaScript在线教程|\n|GitHub|JavaScript开源项目与示例代码|\n|Stack Overflow|编程问答社区