# 怎么用JS和API制作天氣Web應用程序
## 目錄
1. [前言](#前言)
2. [項目概述](#項目概述)
3. [技術棧選擇](#技術棧選擇)
4. [獲取天氣API](#獲取天氣api)
5. [搭建基礎HTML結構](#搭建基礎html結構)
6. [CSS樣式設計](#css樣式設計)
7. [JavaScript核心功能實現](#javascript核心功能實現)
8. [處理API響應數據](#處理api響應數據)
9. [錯誤處理與用戶體驗優化](#錯誤處理與用戶體驗優化)
10. [部署與測試](#部署與測試)
11. [進階功能建議](#進階功能建議)
12. [總結](#總結)
## 前言
在當今數字化時代,天氣應用程序已成為人們日常生活中不可或缺的工具。通過Web技術構建天氣應用不僅能提升編程技能,還能深入理解現代Web開發的工作流程。本文將詳細指導您如何使用JavaScript和第三方API創建一個功能完整的天氣Web應用程序。
## 項目概述
我們將構建一個具有以下功能的天氣應用:
- 實時天氣數據顯示(溫度、濕度、風速等)
- 5天天氣預報
- 基于用戶位置的自動定位
- 城市搜索功能
- 響應式設計適配各種設備
## 技術棧選擇
### 核心組件
- **HTML5**:頁面結構
- **CSS3**:樣式和布局
- **JavaScript (ES6+)**:交互邏輯
- **Fetch API**:數據獲取
### 天氣API選擇
推薦使用以下API之一:
1. OpenWeatherMap (免費版可用)
2. WeatherAPI.com
3. AccuWeather API
本文以OpenWeatherMap為例,因其免費層足夠用于學習項目。
## 獲取天氣API
### 注冊OpenWeatherMap
1. 訪問 [OpenWeatherMap官網](https://openweathermap.org/)
2. 注冊免費賬戶
3. 在控制面板獲取API Key
### API端點了解
關鍵端點:
- 當前天氣:`api.openweathermap.org/data/2.5/weather?q={city}&appid={API key}`
- 5天預報:`api.openweathermap.org/data/2.5/forecast?q={city}&appid={API key}`
## 搭建基礎HTML結構
```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="styles.css">
</head>
<body>
<div class="app-container">
<header>
<h1>天氣追蹤器</h1>
<div class="search-container">
<input type="text" id="city-input" placeholder="輸入城市名稱...">
<button id="search-btn">搜索</button>
<button id="location-btn">使用當前位置</button>
</div>
</header>
<main>
<div class="current-weather">
<div class="weather-info">
<h2 id="city-name">--</h2>
<div class="temp" id="current-temp">--°C</div>
<div class="weather-description" id="weather-desc">--</div>
</div>
<div class="weather-details">
<div>濕度: <span id="humidity">--%</span></div>
<div>風速: <span id="wind-speed">-- m/s</span></div>
<div>氣壓: <span id="pressure">-- hPa</span></div>
</div>
</div>
<div class="forecast" id="forecast-container">
<h3>5天預報</h3>
<div class="forecast-items"></div>
</div>
</main>
</div>
<script src="app.js"></script>
</body>
</html>
/* 基礎重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
padding: 20px;
}
.app-container {
max-width: 800px;
margin: 0 auto;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
header {
padding: 20px;
background: linear-gradient(to right, #4b6cb7, #182848);
color: white;
text-align: center;
}
.search-container {
margin-top: 15px;
display: flex;
gap: 10px;
}
input, button {
padding: 10px 15px;
border: none;
border-radius: 5px;
}
input {
flex-grow: 1;
}
button {
background-color: #ff7e5f;
color: white;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #feb47b;
}
.current-weather {
display: flex;
padding: 30px;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #eee;
}
.weather-info {
text-align: center;
}
.temp {
font-size: 3rem;
font-weight: bold;
margin: 10px 0;
}
.weather-details {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
}
.forecast {
padding: 20px;
}
.forecast-items {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 15px;
margin-top: 15px;
}
.forecast-item {
background-color: rgba(255, 255, 255, 0.7);
padding: 15px;
border-radius: 10px;
text-align: center;
}
/* 響應式設計 */
@media (max-width: 600px) {
.current-weather {
flex-direction: column;
}
.search-container {
flex-direction: column;
}
}
// 配置常量
const API_KEY = 'your_api_key_here';
const BASE_URL = 'https://api.openweathermap.org/data/2.5';
// DOM元素
const cityInput = document.getElementById('city-input');
const searchBtn = document.getElementById('search-btn');
const locationBtn = document.getElementById('location-btn');
const cityName = document.getElementById('city-name');
const currentTemp = document.getElementById('current-temp');
const weatherDesc = document.getElementById('weather-desc');
const humidity = document.getElementById('humidity');
const windSpeed = document.getElementById('wind-speed');
const pressure = document.getElementById('pressure');
const forecastContainer = document.querySelector('.forecast-items');
// 事件監聽器
searchBtn.addEventListener('click', searchWeather);
locationBtn.addEventListener('click', getLocationWeather);
cityInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') searchWeather();
});
// 獲取天氣數據
async function fetchWeather(city) {
try {
// 獲取當前天氣
const currentResponse = await fetch(
`${BASE_URL}/weather?q=${city}&units=metric&appid=${API_KEY}`
);
if (!currentResponse.ok) {
throw new Error('城市未找到');
}
const currentData = await currentResponse.json();
// 獲取預報數據
const forecastResponse = await fetch(
`${BASE_URL}/forecast?q=${city}&units=metric&appid=${API_KEY}`
);
const forecastData = await forecastResponse.json();
return { current: currentData, forecast: forecastData };
} catch (error) {
console.error('獲取天氣數據失敗:', error);
throw error;
}
}
// 搜索天氣
async function searchWeather() {
const city = cityInput.value.trim();
if (!city) return;
try {
const weatherData = await fetchWeather(city);
updateUI(weatherData);
} catch (error) {
alert(error.message);
}
}
// 使用地理位置獲取天氣
function getLocationWeather() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
async (position) => {
const { latitude, longitude } = position.coords;
try {
// 反向地理編碼獲取城市名稱
const response = await fetch(
`https://api.openweathermap.org/geo/1.0/reverse?lat=${latitude}&lon=${longitude}&limit=1&appid=${API_KEY}`
);
const locationData = await response.json();
const city = locationData[0].name;
cityInput.value = city;
const weatherData = await fetchWeather(city);
updateUI(weatherData);
} catch (error) {
alert('獲取位置天氣失敗');
}
},
(error) => {
alert('獲取地理位置失敗: ' + error.message);
}
);
} else {
alert('您的瀏覽器不支持地理位置功能');
}
}
// 更新UI
function updateUI(data) {
const { current, forecast } = data;
// 更新當前天氣
cityName.textContent = `${current.name}, ${current.sys.country}`;
currentTemp.textContent = `${Math.round(current.main.temp)}°C`;
weatherDesc.textContent = current.weather[0].description;
humidity.textContent = `${current.main.humidity}%`;
windSpeed.textContent = `${current.wind.speed} m/s`;
pressure.textContent = `${current.main.pressure} hPa`;
// 更新預報
updateForecastUI(forecast);
}
// 更新預報UI
function updateForecastUI(forecastData) {
// 清空現有內容
forecastContainer.innerHTML = '';
// 按天分組預報數據
const dailyForecasts = {};
forecastData.list.forEach(item => {
const date = new Date(item.dt * 1000).toLocaleDateString();
if (!dailyForecasts[date]) {
dailyForecasts[date] = [];
}
dailyForecasts[date].push(item);
});
// 顯示每天預報(最多5天)
Object.keys(dailyForecasts).slice(0, 5).forEach(date => {
const dayData = dailyForecasts[date][0]; // 取當天的第一個時間點數據
const forecastItem = document.createElement('div');
forecastItem.className = 'forecast-item';
const dateObj = new Date(dayData.dt * 1000);
const dayName = dateObj.toLocaleDateString('zh-CN', { weekday: 'long' });
forecastItem.innerHTML = `
<div class="forecast-day">${dayName}</div>
<img src="https://openweathermap.org/img/wn/${dayData.weather[0].icon}@2x.png"
alt="${dayData.weather[0].description}" width="50">
<div class="forecast-temp">
<span>${Math.round(dayData.main.temp_max)}°</span> /
<span>${Math.round(dayData.main.temp_min)}°</span>
</div>
<div class="forecast-desc">${dayData.weather[0].description}</div>
`;
forecastContainer.appendChild(forecastItem);
});
}
function formatDate(timestamp) {
const date = new Date(timestamp * 1000);
return date.toLocaleDateString('zh-CN', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
});
}
function getWeatherIcon(iconCode) {
return `https://openweathermap.org/img/wn/${iconCode}@2x.png`;
}
// 添加加載狀態
function setLoadingState(isLoading) {
if (isLoading) {
document.body.classList.add('loading');
} else {
document.body.classList.remove('loading');
}
}
// 修改后的搜索函數
async function searchWeather() {
const city = cityInput.value.trim();
if (!city) return;
try {
setLoadingState(true);
const weatherData = await fetchWeather(city);
updateUI(weatherData);
saveLastCity(city);
} catch (error) {
alert(error.message);
} finally {
setLoadingState(false);
}
}
// 本地存儲
function saveLastCity(city) {
localStorage.setItem('lastCity', city);
}
function getLastCity() {
return localStorage.getItem('lastCity');
}
// 初始化時加載上次查詢的城市
window.addEventListener('DOMContentLoaded', () => {
const lastCity = getLastCity();
if (lastCity) {
cityInput.value = lastCity;
searchWeather();
}
});
通過本教程,您已經學會了如何使用JavaScript和天氣API構建一個功能完善的天氣Web應用程序。這個項目涵蓋了現代Web開發的多個關鍵方面,包括: - API集成與數據處理 - 異步JavaScript編程 - DOM操作與UI更新 - 錯誤處理與用戶體驗 - 響應式設計實現
您可以根據需要進一步擴展此應用,添加更多功能或優化現有實現。這個項目不僅是一個實用的天氣工具,也是展示您前端開發技能的優秀作品。
字數統計:約5050字(根據實際需要可調整細節部分) “`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。