9.30 天气预报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>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Microsoft YaHei', Arial, sans-serif;
            background: linear-gradient(135deg, #74b9ff 0%, #0984e3 100%);
            min-height: 100vh;
            padding: 20px;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 20px;
            box-shadow: 0 15px 35px rgba(0,0,0,0.1);
            padding: 30px;
            border: 3px solid #74b9ff;
        }
        
        .header {
            text-align: center;
            margin-bottom: 30px;
        }
        
        .student-info {
            background: linear-gradient(45deg, #fd79a8, #e84393);
            color: white;
            padding: 12px 25px;
            border-radius: 25px;
            margin-bottom: 15px;
            display: inline-block;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
            font-weight: bold;
        }
        
        .student-name, .student-id {
            font-size: 1.2em;
            margin: 0 15px;
        }
        
        .header h1 {
            color: #2d3436;
            font-size: 2.8em;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
            margin-bottom: 10px;
            background: linear-gradient(45deg, #00cec9, #00b894);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
        }
        
        .header p {
            color: #636e72;
            font-size: 1.3em;
            margin-bottom: 20px;
        }
        
        .search-section {
            background: #f8f9fa;
            padding: 25px;
            border-radius: 15px;
            margin-bottom: 30px;
            border: 2px solid #dfe6e9;
        }
        
        .search-form {
            display: flex;
            gap: 15px;
            align-items: center;
            justify-content: center;
            flex-wrap: wrap;
        }
        
        .search-input {
            flex: 1;
            min-width: 300px;
            padding: 15px 20px;
            border: 2px solid #b2bec3;
            border-radius: 50px;
            font-size: 1.1em;
            outline: none;
            transition: all 0.3s ease;
        }
        
        .search-input:focus {
            border-color: #74b9ff;
            box-shadow: 0 0 10px rgba(116, 185, 255, 0.3);
        }
        
        .search-btn {
            padding: 15px 30px;
            background: linear-gradient(45deg, #00b894, #00cec9);
            color: white;
            border: none;
            border-radius: 50px;
            font-size: 1.1em;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
        }
        
        .search-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 12px rgba(0,0,0,0.2);
        }
        
        .weather-display {
            display: none;
        }
        
        .current-weather {
            background: linear-gradient(135deg, #a29bfe 0%, #6c5ce7 100%);
            color: white;
            padding: 30px;
            border-radius: 20px;
            margin-bottom: 25px;
            text-align: center;
            box-shadow: 0 10px 20px rgba(0,0,0,0.1);
        }
        
        .city-name {
            font-size: 2.5em;
            margin-bottom: 10px;
            font-weight: bold;
        }
        
        .temperature {
            font-size: 4em;
            font-weight: bold;
            margin: 20px 0;
        }
        
        .weather-info {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-top: 20px;
        }
        
        .info-item {
            background: rgba(255,255,255,0.2);
            padding: 15px;
            border-radius: 10px;
            backdrop-filter: blur(10px);
        }
        
        .forecast {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin-top: 30px;
        }
        
        .forecast-day {
            background: white;
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
            text-align: center;
            border: 2px solid #dfe6e9;
            transition: all 0.3s ease;
        }
        
        .forecast-day:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 25px rgba(0,0,0,0.15);
            border-color: #74b9ff;
        }
        
        .forecast-date {
            font-weight: bold;
            color: #2d3436;
            margin-bottom: 10px;
            font-size: 1.2em;
        }
        
        .forecast-temp {
            font-size: 1.8em;
            font-weight: bold;
            color: #e17055;
            margin: 10px 0;
        }
        
        .forecast-desc {
            color: #636e72;
            margin-bottom: 10px;
        }
        
        .loading {
            text-align: center;
            padding: 40px;
            display: none;
        }
        
        .spinner {
            border: 4px solid #f3f3f3;
            border-top: 4px solid #74b9ff;
            border-radius: 50%;
            width: 50px;
            height: 50px;
            animation: spin 1s linear infinite;
            margin: 0 auto 20px;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        .error-message {
            background: #ff7675;
            color: white;
            padding: 20px;
            border-radius: 10px;
            text-align: center;
            margin: 20px 0;
            display: none;
        }
        
        .api-info {
            background: #ffeaa7;
            padding: 15px;
            border-radius: 10px;
            margin-top: 20px;
            text-align: center;
            color: #2d3436;
            font-size: 0.9em;
        }
        
        @media (max-width: 768px) {
            .search-form {
                flex-direction: column;
            }
            
            .search-input {
                min-width: auto;
                width: 100%;
            }
            
            .temperature {
                font-size: 3em;
            }
            
            .city-name {
                font-size: 2em;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🌤️ 城市天气查询系统</h1>
            <p>查询全球城市的实时天气和未来天气预报</p>
        </div>
        
        <div class="search-section">
            <div class="search-form">
                <input type="text" class="search-input" id="cityInput" 
                       placeholder="请输入城市名称(如:北京、上海、New York)" 
                       value="北京">
                <button class="search-btn" onclick="searchWeather()">
                    🔍 查询天气
                </button>
            </div>
        </div>
        
        <div class="loading" id="loading">
            <div class="spinner"></div>
            <p>正在获取天气数据,请稍候...</p>
        </div>
        
        <div class="error-message" id="errorMessage">
            <!-- 错误信息将在这里显示 -->
        </div>
        
        <div class="weather-display" id="weatherDisplay">
            <div class="current-weather" id="currentWeather">
                <!-- 当前天气信息将在这里显示 -->
            </div>
            
            <div class="forecast" id="forecast">
                <!-- 天气预报信息将在这里显示 -->
            </div>
        </div>
    </div>

    <script>
        const WEATHER_API_URL = 'https://api.lolimi.cn/API/weather/api.php';
      
        async function fetchRealWeather(city) {
            try {
                // 构建请求参数
                const params = {
                    city: city,
                    type: 'json'
                };
                
                // 构建查询字符串
                const query = new URLSearchParams(params).toString();
                const fullUrl = WEATHER_API_URL + '?' + query;
                
                // 发送请求
                const response = await fetch(fullUrl, {
                    method: 'GET',
                    mode: 'no-cors', // 使用no-cors模式绕过CORS限制
                    headers: {
                        'Accept': '*/*',
                        'Content-Type': 'application/x-www-form-urlencoded',
                        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
                    }
                });
                

                if (response.ok || response.type === 'opaque') {
                    // 尝试解析响应,如果失败则说明API可能不支持no-cors
                    try {
                        const data = await response.json();
                        if (data.code === 1) {
                            return data.data;
                        } else {
                            throw new Error(data.text || '获取天气数据失败');
                        }
                    } catch (parseError) {
                        // 如果无法解析JSON,尝试使用代理服务
                        return await fetchWithProxy(city);
                    }
                } else {
                    throw new Error(`请求失败,状态码: ${response.status}`);
                }
                
            } catch (error) {
                // 如果直接请求失败,尝试使用代理服务
                return await fetchWithProxy(city);
            }
        }
        
        // 备用方案:使用代理服务
        async function fetchWithProxy(city) {
            const proxyServices = [
                'https://api.allorigins.win/raw?url=',
                'https://corsproxy.io/?',
                'https://proxy.cors.sh/'
            ];
            
            const apiUrl = `${WEATHER_API_URL}?city=${encodeURIComponent(city)}&type=json`;
            
            for (const proxyUrl of proxyServices) {
                try {
                    const response = await fetch(proxyUrl + encodeURIComponent(apiUrl), {
                        method: 'GET',
                        headers: {
                            'Accept': '*/*',
                            'Content-Type': 'application/x-www-form-urlencoded'
                        }
                    });
                    
                    if (response.ok) {
                        const data = await response.json();
                        if (data.code === 1) {
                            return data.data;
                        } else {
                            throw new Error(data.text || '获取天气数据失败');
                        }
                    }
                } catch (error) {
                    console.log(`代理服务 ${proxyUrl} 失败:`, error);
                    continue;
                }
            }
            
            throw new Error('所有代理服务均不可用,请检查网络连接');
        }
        
        // 显示/隐藏加载动画
        function showLoading(show) {
            document.getElementById('loading').style.display = show ? 'block' : 'none';
        }
        
        // 显示错误信息
        function showError(message) {
            const errorDiv = document.getElementById('errorMessage');
            errorDiv.innerHTML = `❌ ${message}`;
            errorDiv.style.display = 'block';
            setTimeout(() => {
                errorDiv.style.display = 'none';
            }, 5000);
        }
        
        // 搜索天气
        async function searchWeather() {
            const cityInput = document.getElementById('cityInput');
            const city = cityInput.value.trim();
            
            if (!city) {
                showError('请输入城市名称');
                return;
            }
            
            showLoading(true);
            document.getElementById('weatherDisplay').style.display = 'none';
            
            try {
                // 调用真实天气API
                const weatherData = await fetchRealWeather(city);
                displayWeather(city, weatherData);
                
            } catch (error) {
                console.error('获取天气数据失败:', error);
                showError('获取天气数据失败,请检查网络连接或稍后重试');
            } finally {
                showLoading(false);
            }
        }
        
        // 显示天气信息
        function displayWeather(city, data) {
            const current = data.current;
            
            // 显示当前天气
            const currentWeatherDiv = document.getElementById('currentWeather');
            currentWeatherDiv.innerHTML = `
                <div class="city-name">${current.city}</div>
                <div class="temperature">${current.temp}°C</div>
                <div style="font-size: 1.5em; margin-bottom: 10px;">
                    ${getWeatherEmoji(current.weather)} ${current.weather}
                </div>
                <div style="font-size: 1.1em; opacity: 0.9;">日期: ${current.date} ${current.time}</div>
                
                <!-- 简化信息显示 -->
                <div class="weather-info">
                    <div class="info-item">
                        <div>💧 湿度</div>
                        <div style="font-size: 1.3em; font-weight: bold;">${current.humidity}</div>
                    </div>
                    <div class="info-item">
                        <div>🌬️ 风向风速</div>
                        <div style="font-size: 1.3em; font-weight: bold;">${current.wind} ${current.windSpeed}</div>
                    </div>
                    <div class="info-item">
                        <div>💨 空气质量</div>
                        <div style="font-size: 1.3em; font-weight: bold;">${current.air_pm25 || 'N/A'}</div>
                    </div>
                    <div class="info-item">
                        <div>${isRaining(current.weather) ? '🌧️ 正在下雨' : '☀️ 无雨'}</div>
                        <div style="font-size: 1.3em; font-weight: bold;">${isRaining(current.weather) ? '是' : '否'}</div>
                    </div>
                </div>
            `;
            
            // 显示未来几天天气预报(模拟数据)
            const forecastDiv = document.getElementById('forecast');
            const futureWeather = generateFutureWeather(current.weather, current.temp);
            
            forecastDiv.innerHTML = `
                <h3 style="text-align: center; margin-bottom: 20px; color: #2d3436;">未来3天天气预报</h3>
                <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;">
                    ${futureWeather.map((day, index) => `
                        <div style="background: #f8f9fa; padding: 15px; border-radius: 10px; border-left: 4px solid #74b9ff; text-align: center;">
                            <div style="font-weight: bold; color: #2d3436; margin-bottom: 10px;">${day.date}</div>
                            <div style="font-size: 2em; margin-bottom: 5px;">${getWeatherEmoji(day.weather)}</div>
                            <div style="color: #2d3436; font-weight: bold; margin-bottom: 5px;">${day.weather}</div>
                            <div style="color: #e17055; font-weight: bold; font-size: 1.2em;">${day.temp}°C</div>
                            <div style="color: #636e72; font-size: 0.9em; margin-top: 5px;">${day.rain ? '🌧️ 有雨' : '☀️ 无雨'}</div>
                        </div>
                    `).join('')}
                </div>
            `;
            
            // 显示天气信息区域
            document.getElementById('weatherDisplay').style.display = 'block';
            
            // 滚动到天气信息区域
            document.getElementById('weatherDisplay').scrollIntoView({ 
                behavior: 'smooth' 
            });
        }
        
        // 判断是否下雨
        function isRaining(weather) {
            const rainKeywords = ['雨', '雷', '阵雨', '暴雨', '小雨', '中雨', '大雨'];
            return rainKeywords.some(keyword => weather.includes(keyword));
        }
        
        // 生成未来几天天气预报(模拟数据)
        function generateFutureWeather(currentWeather, currentTemp) {
            const today = new Date();
            const weatherTypes = ['晴', '多云', '阴', '小雨', '中雨', '大雨', '雷阵雨'];
            const futureWeather = [];
            
            // 基于当前天气生成未来天气趋势
            let currentWeatherIndex = weatherTypes.indexOf(currentWeather);
            if (currentWeatherIndex === -1) currentWeatherIndex = 0;
            
            for (let i = 1; i <= 3; i++) {
                const futureDate = new Date(today);
                futureDate.setDate(today.getDate() + i);
                
                // 模拟天气变化趋势
                const weatherChange = Math.floor(Math.random() * 3) - 1; // -1, 0, 1
                let weatherIndex = Math.max(0, Math.min(weatherTypes.length - 1, currentWeatherIndex + weatherChange));
                
                const weather = weatherTypes[weatherIndex];
                const tempChange = Math.floor(Math.random() * 5) - 2; // -2到+2度变化
                const temp = Math.max(-10, Math.min(40, parseInt(currentTemp) + tempChange));
                
                futureWeather.push({
                    date: `${futureDate.getMonth() + 1}月${futureDate.getDate()}日`,
                    weather: weather,
                    temp: temp,
                    rain: isRaining(weather)
                });
            }
            
            return futureWeather;
        }
        
        // 根据天气描述获取对应的emoji
        function getWeatherEmoji(weather) {
            const emojiMap = {
                '晴': '☀️',
                '多云': '⛅',
                '阴': '☁️',
                '雨': '🌧️',
                '小雨': '🌦️',
                '中雨': '🌧️',
                '大雨': '🌧️',
                '暴雨': '⛈️',
                '雷阵雨': '⛈️',
                '雪': '❄️',
                '小雪': '🌨️',
                '中雪': '❄️',
                '大雪': '❄️',
                '雾': '🌫️',
                '霾': '🌫️'
            };
            
            for (const [key, emoji] of Object.entries(emojiMap)) {
                if (weather.includes(key)) {
                    return emoji;
                }
            }
            return '🌤️';
        }
        
        // 回车键搜索
        document.getElementById('cityInput').addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                searchWeather();
            }
        });
        
        // 页面加载时显示欢迎信息
        window.onload = function() {
            // 可以在这里添加页面加载后的初始化代码
            console.log('天气查询系统已加载');
        };
        
        // 实际API调用函数(注释掉,因为需要真实API密钥)
        /*
        async function fetchRealWeather(city) {
            try {
                // 获取当前天气
                const currentResponse = await fetch(
                    `${BASE_URL}/weather?q=${city}&appid=${API_KEY}&units=metric&lang=zh_cn`
                );
                
                if (!currentResponse.ok) {
                    throw new Error('城市未找到');
                }
                
                const currentData = await currentResponse.json();
                
                // 获取天气预报
                const forecastResponse = await fetch(
                    `${BASE_URL}/forecast?q=${city}&appid=${API_KEY}&units=metric&lang=zh_cn`
                );
                
                const forecastData = await forecastResponse.json();
                
                return {
                    current: {
                        temp: Math.round(currentData.main.temp),
                        feels_like: Math.round(currentData.main.feels_like),
                        humidity: currentData.main.humidity,
                        pressure: currentData.main.pressure,
                        wind_speed: currentData.wind.speed,
                        description: currentData.weather[0].description,
                        icon: currentData.weather[0].icon
                    },
                    forecast: forecastData.list.slice(0, 5).map(item => ({
                        date: new Date(item.dt * 1000).toLocaleDateString('zh-CN'),
                        temp: Math.round(item.main.temp),
                        description: item.weather[0].description,
                        icon: item.weather[0].icon
                    }))
                };
                
            } catch (error) {
                throw error;
            }
        }
        */
    </script>
</body>
</html>
posted @ 2026-01-03 00:24  liu某人  阅读(25)  评论(0)    收藏  举报