引言
一款采用现代前端技术构建的美观、实用的天气预报单页应用,提供直观的天气信息展示和流畅的用户体验。
一 项目概述
本项目是一个纯前端实现的天气预报单页应用,结合了精美的UI设计和流畅的动画效果,为用户提供实时天气信息和未来天气预报。应用支持响应式设计,可在各种设备上完美展示。
二 功能特性
- **实时天气信息**:显示当前温度、体感温度、湿度、风速、气压等详细气象数据
- **未来天气预报**:提供未来几天的天气趋势预测
- **动态天气图标**:根据天气状况展示相应的动画效果(太阳旋转、云朵浮动、雨滴下落等)
- **数据可视化**:使用Chart.js展示温度变化趋势图表
- **响应式设计**:完美适配手机、平板和桌面设备
- **优雅的UI**:采用蓝色渐变背景和半透明卡片设计,营造清新、专业的视觉效果
- **平滑动画**:页面元素添加入场动画和平滑过渡效果
三 技术栈
- **HTML5**:构建语义化的页面结构
- **Tailwind CSS v3**:快速实现响应式布局和现代化UI设计
- **JavaScript (ES6+)**:处理交互逻辑和数据展示
- **Font Awesome**:提供丰富的天气图标
- **Chart.js**:用于绘制温度变化趋势图表
四 快速开始
indel.html 文件启动
五 核心代码展示
下面是应用中最核心的功能实现代码,展示了天气数据处理、UI更新、动态效果和数据可视化的关键部分:
5.1. 天气数据获取与处理
function getWeatherData(city) {
showLoading();
// 模拟API调用延迟
setTimeout(() => {
try {
// 在实际应用中,这里应该是真实的API调用
// 这里使用模拟数据进行演示
useMockData(city);
} catch (error) {
console.error('获取天气数据失败:', error);
showToast('获取天气数据失败,请稍后重试');
useMockData(city); // 即使API失败,也使用模拟数据
} finally {
hideLoading();
}
}, 1500);
}
5.2天气 UI 更新系统
// 更新天气UI
function updateWeatherUI(data) {
// 更新城市名称
document.getElementById('city-name').textContent = data.city;
// 更新当前时间
document.getElementById('current-time').textContent = getCurrentTime();
// 获取当前天气数据
const currentWeather = data.data[0];
// 更新当前天气信息
document.getElementById('current-temp').textContent = currentWeather.temperature;
document.getElementById('current-weather').textContent = currentWeather.weather;
document.getElementById('current-wind').textContent = currentWeather.wind;
document.getElementById('air-quality').textContent = currentWeather.air_quality;
// 更新天气图标
const weatherIconContainer = document.getElementById('weather-icon');
weatherIconContainer.innerHTML = getWeatherIcon(currentWeather.weather);
// 更新预报卡片
updateForecastCards(data.data);
// 更新温度图表
updateTemperatureChart(data.data);
// 滚动到当前天气
document.getElementById('current').scrollIntoView({ behavior: 'smooth' });
// 添加动画效果
weatherContent.classList.remove('animate-fade-in');
void weatherContent.offsetWidth; // 触发重绘
weatherContent.classList.add('animate-fade-in');
}
// 更新预报卡片
function updateForecastCards(forecastData) {
const forecastContainer = document.querySelector('#forecast .grid');
forecastContainer.innerHTML = '';
forecastData.forEach(day => {
const card = document.createElement('div');
card.className = 'bg-white rounded-xl shadow-md p-4 card-hover';
// 获取天气图标
const weatherIcon = getWeatherIcon(day.weather);
card.innerHTML = `
<div class="text-center">
<p class="font-medium text-gray-700">${day.date}</p>
${weatherIcon}
<p class="text-gray-600">${day.weather}</p>
<p class="font-bold mt-2">${day.temperature}</p>
<p class="text-sm text-gray-500 mt-1">${day.wind}</p>
</div>
`;
forecastContainer.appendChild(card);
});
}
5.3. 动态天气图标系统
// 获取天气图标
function getWeatherIcon(weather) {
let iconClass = '';
let animationClass = '';
if (weather.includes('晴')) {
iconClass = 'fa-sun';
animationClass = 'animate-sun';
} else if (weather.includes('云')) {
iconClass = 'fa-cloud';
animationClass = 'animate-cloud';
} else if (weather.includes('雨')) {
iconClass = 'fa-cloud-rain';
animationClass = 'animate-rain';
} else if (weather.includes('雪')) {
iconClass = 'fa-snowflake';
animationClass = 'animate-snow';
} else if (weather.includes('雾')) {
iconClass = 'fa-smog';
animationClass = 'animate-fog';
} else if (weather.includes('雷')) {
iconClass = 'fa-bolt';
animationClass = 'animate-thunder';
} else {
iconClass = 'fa-cloud-sun';
animationClass = '';
}
return `<i class="fa ${iconClass} text-primary text-4xl ${animationClass}"></i>`;
}
5.4 数据可视化实现
// 更新温度图表
function updateTemperatureChart(forecastData) {
const ctx = document.getElementById('temperature-chart').getContext('2d');
// 销毁已存在的图表
if (window.temperatureChart) {
window.temperatureChart.destroy();
}
const dates = forecastData.map(day => day.date);
const minTemps = forecastData.map(day => {
return parseInt(day.temperature.split('-')[0].replace('℃', ''));
});
const maxTemps = forecastData.map(day => {
return parseInt(day.temperature.split('-')[1].replace('℃', ''));
});
// 创建新图表
window.temperatureChart = new Chart(ctx, {
type: 'line',
data: {
labels: dates,
datasets: [
{
label: '最高温度',
data: maxTemps,
borderColor: '#F97316',
backgroundColor: 'rgba(249, 115, 22, 0.1)',
borderWidth: 2,
tension: 0.3,
fill: false,
pointBackgroundColor: '#F97316',
pointRadius: 4
},
{
label: '最低温度',
data: minTemps,
borderColor: '#3B82F6',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
borderWidth: 2,
tension: 0.3,
fill: false,
pointBackgroundColor: '#3B82F6',
pointRadius: 4
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
// 更多配置选项...
}
});
}
5.5 页面交互也用户体验化
// 移动端菜单切换
mobileMenuButton.addEventListener('click', () => {
mobileMenu.classList.toggle('hidden');
});
// 城市搜索
searchButton.addEventListener('click', () => {
const city = citySearch.value.trim();
if (city) {
getWeatherData(city);
} else {
showToast('请输入城市名称');
}
});
// 热门城市点击
const cityTags = document.querySelectorAll('.city-tag');
cityTags.forEach(tag => {
tag.addEventListener('click', () => {
const city = tag.textContent;
citySearch.value = city;
getWeatherData(city);
});
});
// 显示提示信息
function showToast(message) {
// 创建toast元素
const toast = document.createElement('div');
toast.className = 'fixed top-20 left-1/2 transform -translate-x-1/2 bg-dark text-white px-6 py-3 rounded-lg shadow-lg z-50 transition-all duration-300 opacity-0';
toast.textContent = message;
document.body.appendChild(toast);
// 显示toast
setTimeout(() => {
toast.classList.remove('opacity-0');
toast.classList.add('opacity-100');
}, 10);
// 3秒后隐藏
setTimeout(() => {
toast.classList.remove('opacity-100');
toast.classList.add('opacity-0');
setTimeout(() => {
document.body.removeChild(toast);
}, 300);
}, 3000);
}
5.6 动态效果实现
/* 太阳动画 */
@keyframes sun {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 云朵动画 */
@keyframes cloud {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-5px);
}
}
/* 雨滴动画 */
@keyframes fall {
0% {
transform: translateY(-20px);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(40px);
opacity: 0;
}
}
/* 雪花动画 */
@keyframes snow {
0% {
transform: translateY(-20px) rotate(0deg);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: translateY(20px) rotate(360deg);
opacity: 0;
}
}
/* 雾动画 */
@keyframes fog {
0%, 100% {
opacity: 0.6;
}
50% {
opacity: 0.3;
}
}
六 设计亮点
6.1 视觉设计
- **渐变背景**:使用蓝色系渐变作为页面背景,营造天空的感觉
- **半透明卡片**:采用半透明的白色卡片展示天气信息,创造层次感
- **阴影效果**:为卡片添加柔和的阴影,增强立体感
- **圆角设计**:统一使用圆角元素,营造亲和、现代的视觉感受
- **文本层次**:通过不同的字体大小、粗细和颜色,建立清晰的文本信息层次结构
6.2 动态效果
- **太阳动画**:缓慢旋转效果,模拟太阳东升西落
- **云朵动画**:上下浮动效果,仿佛在天空中轻轻飘动
- **雨滴动画**:自然下落效果,营造下雨的真实感
- **雪花动画**:轻盈飘落效果,模拟雪花从天空降落
- **雾动画**:淡入淡出效果,表现雾气的朦胧感
- **雷电动画**:闪烁效果,呈现雷暴天气的特点