60sapi接口搭建完毕,数据库连接测试成功,登录注册部分简单完成
This commit is contained in:
252
frontend/react-app/public/60sapi/实用功能/实时天气/js/script.js
vendored
Normal file
252
frontend/react-app/public/60sapi/实用功能/实时天气/js/script.js
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
// 天气查询应用
|
||||
class WeatherApp {
|
||||
constructor() {
|
||||
this.apiEndpoints = [
|
||||
'https://60s-cf.viki.moe',
|
||||
'https://60s.viki.moe',
|
||||
'https://60s.b23.run',
|
||||
'https://60s.114128.xyz',
|
||||
'https://60s-cf.114128.xyz'
|
||||
];
|
||||
this.currentEndpointIndex = 0;
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.bindEvents();
|
||||
// 页面加载时自动查询北京天气
|
||||
this.searchWeather('北京');
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
const searchBtn = document.getElementById('searchBtn');
|
||||
const cityInput = document.getElementById('cityInput');
|
||||
|
||||
searchBtn.addEventListener('click', () => {
|
||||
const city = cityInput.value.trim();
|
||||
if (city) {
|
||||
this.searchWeather(city);
|
||||
} else {
|
||||
this.showError('请输入城市名称');
|
||||
}
|
||||
});
|
||||
|
||||
cityInput.addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
const city = cityInput.value.trim();
|
||||
if (city) {
|
||||
this.searchWeather(city);
|
||||
} else {
|
||||
this.showError('请输入城市名称');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 防止输入框为空时查询
|
||||
cityInput.addEventListener('input', () => {
|
||||
const searchBtn = document.getElementById('searchBtn');
|
||||
searchBtn.disabled = !cityInput.value.trim();
|
||||
});
|
||||
}
|
||||
|
||||
async searchWeather(city) {
|
||||
this.showLoading();
|
||||
|
||||
for (let i = 0; i < this.apiEndpoints.length; i++) {
|
||||
try {
|
||||
const endpoint = this.apiEndpoints[this.currentEndpointIndex];
|
||||
const response = await this.fetchWeatherData(endpoint, city);
|
||||
|
||||
if (response && response.code === 200) {
|
||||
this.displayWeatherData(response.data);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`API ${this.apiEndpoints[this.currentEndpointIndex]} 请求失败:`, error);
|
||||
}
|
||||
|
||||
// 切换到下一个API端点
|
||||
this.currentEndpointIndex = (this.currentEndpointIndex + 1) % this.apiEndpoints.length;
|
||||
}
|
||||
|
||||
// 所有API都失败了
|
||||
this.showError('获取天气信息失败,请检查网络连接或稍后重试');
|
||||
}
|
||||
|
||||
async fetchWeatherData(endpoint, city) {
|
||||
const url = `${endpoint}/v2/weather?query=${encodeURIComponent(city)}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
timeout: 10000
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
displayWeatherData(data) {
|
||||
const { location, realtime } = data;
|
||||
|
||||
// 显示位置信息
|
||||
document.getElementById('locationName').textContent = location.formatted;
|
||||
document.getElementById('locationDetail').textContent =
|
||||
`${location.province} ${location.city} | 邮编: ${location.zip_code}`;
|
||||
|
||||
// 显示当前天气
|
||||
document.getElementById('temperature').textContent = realtime.temperature;
|
||||
document.getElementById('weatherCondition').textContent = realtime.weather;
|
||||
|
||||
// 体感温度转换(API返回的是华氏度,需要转换为摄氏度)
|
||||
const feelsLikeCelsius = this.fahrenheitToCelsius(realtime.temperature_feels_like);
|
||||
document.getElementById('feelsLike').textContent =
|
||||
`体感温度 ${feelsLikeCelsius}°C`;
|
||||
|
||||
// 显示天气详情
|
||||
document.getElementById('humidity').textContent = `${realtime.humidity}%`;
|
||||
document.getElementById('windDirection').textContent = realtime.wind_direction;
|
||||
document.getElementById('windStrength').textContent = realtime.wind_strength;
|
||||
document.getElementById('pressure').textContent = `${realtime.pressure} hPa`;
|
||||
document.getElementById('visibility').textContent = realtime.visibility;
|
||||
|
||||
// 空气质量显示
|
||||
const aqiElement = document.getElementById('aqi');
|
||||
aqiElement.textContent = `${realtime.aqi} (PM2.5: ${realtime.pm25})`;
|
||||
aqiElement.className = this.getAQIClass(realtime.aqi);
|
||||
|
||||
// 显示生活指数
|
||||
const lifeIndex = realtime.life_index;
|
||||
this.displayLifeIndex('comfort', lifeIndex.comfort);
|
||||
this.displayLifeIndex('clothing', lifeIndex.clothing);
|
||||
this.displayLifeIndex('umbrella', lifeIndex.umbrella);
|
||||
this.displayLifeIndex('uv', lifeIndex.uv);
|
||||
this.displayLifeIndex('travel', lifeIndex.travel);
|
||||
this.displayLifeIndex('sport', lifeIndex.sport);
|
||||
|
||||
// 显示更新时间
|
||||
document.getElementById('updateTime').textContent =
|
||||
`${realtime.updated} (${realtime.updated_at})`;
|
||||
|
||||
this.showWeatherContainer();
|
||||
}
|
||||
|
||||
displayLifeIndex(type, indexData) {
|
||||
const levelElement = document.getElementById(`${type}Level`);
|
||||
const descElement = document.getElementById(`${type}Desc`);
|
||||
|
||||
if (levelElement && descElement && indexData) {
|
||||
levelElement.textContent = indexData.level;
|
||||
descElement.textContent = indexData.desc;
|
||||
|
||||
// 根据指数级别设置颜色
|
||||
levelElement.className = this.getIndexLevelClass(indexData.level);
|
||||
}
|
||||
}
|
||||
|
||||
getAQIClass(aqi) {
|
||||
if (aqi <= 50) return 'aqi-good';
|
||||
if (aqi <= 100) return 'aqi-moderate';
|
||||
if (aqi <= 150) return 'aqi-unhealthy-sensitive';
|
||||
if (aqi <= 200) return 'aqi-unhealthy';
|
||||
if (aqi <= 300) return 'aqi-very-unhealthy';
|
||||
return 'aqi-hazardous';
|
||||
}
|
||||
|
||||
getIndexLevelClass(level) {
|
||||
const levelMap = {
|
||||
'优': 'level-excellent',
|
||||
'良': 'level-good',
|
||||
'适宜': 'level-suitable',
|
||||
'舒适': 'level-comfortable',
|
||||
'较适宜': 'level-fairly-suitable',
|
||||
'不宜': 'level-unsuitable',
|
||||
'较不宜': 'level-fairly-unsuitable',
|
||||
'带伞': 'level-bring-umbrella',
|
||||
'最弱': 'level-weakest',
|
||||
'弱': 'level-weak',
|
||||
'中等': 'level-moderate',
|
||||
'强': 'level-strong',
|
||||
'很强': 'level-very-strong'
|
||||
};
|
||||
|
||||
return levelMap[level] || 'level-default';
|
||||
}
|
||||
|
||||
// 华氏度转摄氏度
|
||||
fahrenheitToCelsius(fahrenheit) {
|
||||
const celsius = (fahrenheit - 32) * 5 / 9;
|
||||
return Math.round(celsius * 10) / 10; // 保留一位小数
|
||||
}
|
||||
|
||||
showLoading() {
|
||||
document.getElementById('loading').style.display = 'block';
|
||||
document.getElementById('weatherContainer').style.display = 'none';
|
||||
document.getElementById('errorMessage').style.display = 'none';
|
||||
}
|
||||
|
||||
showWeatherContainer() {
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
document.getElementById('weatherContainer').style.display = 'block';
|
||||
document.getElementById('errorMessage').style.display = 'none';
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
document.getElementById('weatherContainer').style.display = 'none';
|
||||
const errorElement = document.getElementById('errorMessage');
|
||||
errorElement.style.display = 'block';
|
||||
errorElement.querySelector('p').textContent = message;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加生活指数级别样式
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.aqi-good { color: #52c41a; }
|
||||
.aqi-moderate { color: #faad14; }
|
||||
.aqi-unhealthy-sensitive { color: #fa8c16; }
|
||||
.aqi-unhealthy { color: #f5222d; }
|
||||
.aqi-very-unhealthy { color: #a0206e; }
|
||||
.aqi-hazardous { color: #722ed1; }
|
||||
|
||||
.level-excellent, .level-suitable, .level-comfortable { color: #52c41a; }
|
||||
.level-good, .level-fairly-suitable { color: #1890ff; }
|
||||
.level-bring-umbrella, .level-moderate { color: #faad14; }
|
||||
.level-unsuitable, .level-fairly-unsuitable { color: #f5222d; }
|
||||
.level-weakest, .level-weak { color: #52c41a; }
|
||||
.level-strong, .level-very-strong { color: #fa8c16; }
|
||||
.level-default { color: #666; }
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// 页面加载完成后初始化应用
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new WeatherApp();
|
||||
});
|
||||
|
||||
// 添加页面可见性检测,当页面重新可见时刷新数据
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (!document.hidden) {
|
||||
const cityInput = document.getElementById('cityInput');
|
||||
const city = cityInput.value.trim() || '北京';
|
||||
// 延迟1秒刷新,避免频繁请求
|
||||
setTimeout(() => {
|
||||
if (window.weatherApp) {
|
||||
window.weatherApp.searchWeather(city);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
|
||||
// 将应用实例暴露到全局,方便调试和其他功能调用
|
||||
window.weatherApp = null;
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
window.weatherApp = new WeatherApp();
|
||||
});
|
||||
Reference in New Issue
Block a user