1. 为什么我们需要一个桌面版天气应用?
在智能手机普及的时代,很多人可能会质疑桌面天气应用的必要性。但作为一名长期使用多台工作设备的开发者,我发现浏览器标签和手机通知里的天气信息存在几个明显痛点:
- 注意力分散:每次查看天气都需要切换应用或打开浏览器,打断了工作流
- 信息过载:主流天气应用充斥着广告和不必要的社交功能
- 数据不连贯:桌面端和移动端的历史天气数据难以同步对比
- 定制化缺失:无法根据个人需求调整显示要素(如对骑行爱好者重要的风速风向)
我最近用Electron+React开发了一个极简天气应用,核心代码不到500行,却实现了:
- 实时天气与未来3小时预报
- 空气质量指数可视化
- 多城市快速切换
- 桌面通知提醒(如降雨预警)
2. 技术选型与架构设计
2.1 为什么选择Electron?
相比传统桌面开发方案,Electron的优势在这个场景特别明显:
-
跨平台一致性:一套代码打包Win/macOS/Linux应用
-
前端技术栈:能用React/Vue快速构建UI,我的选择是:
- React 18 + TypeScript
- Tailwind CSS for styling
- Zustand状态管理(比Redux更轻量)
-
原生API集成:
javascript复制// 系统通知示例 new Notification('暴雨预警', { body: '1小时后将有大雨,建议携带雨具' })
2.2 天气数据源对接
经过对比多家API,最终选择WeatherAPI.com:
- 免费层提供:实时天气+3天预报
- 无需信用卡即可注册
- 清晰的文档和TypeScript类型定义
关键请求示例:
typescript复制interface WeatherData {
current: {
temp_c: number
condition: { text: string; icon: string }
wind_kph: number
humidity: number
}
forecast: {
forecastday: Array<{
hour: Array<{
time: string
temp_c: number
chance_of_rain: number
}>
}>
}
}
const fetchWeather = async (city: string): Promise<WeatherData> => {
const res = await fetch(
`https://api.weatherapi.com/v1/forecast.json?key=YOUR_KEY&q=${city}&days=1&aqi=yes`
)
return res.json()
}
3. 核心功能实现细节
3.1 主界面布局设计
采用三栏式结构:
- 左侧:城市列表(支持拖拽排序)
- 中间:当前天气可视化
- 右侧:逐小时预报折线图
使用Recharts库实现温度曲线图:
jsx复制<LineChart data={hourlyData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="time" />
<YAxis label={{ value: '℃', angle: -90 }} />
<Line
type="monotone"
dataKey="temp_c"
stroke="#ff6b35"
dot={false}
/>
</LineChart>
3.2 数据缓存策略
为避免频繁调用API:
- 使用localStorage存储最近查询结果
- 设置10分钟过期时间
- 后台静默更新数据
缓存实现代码:
typescript复制const CACHE_EXPIRE = 10 * 60 * 1000 // 10分钟
const getCachedWeather = (city: string) => {
const cached = localStorage.getItem(`weather_${city}`)
if (!cached) return null
const { data, timestamp } = JSON.parse(cached)
if (Date.now() - timestamp > CACHE_EXPIRE) return null
return data
}
4. 打包与分发优化
4.1 减小安装包体积
通过electron-builder配置:
json复制{
"asar": true,
"files": ["dist/**/*"],
"extraResources": [
{
"from": "assets/icons",
"to": "icons"
}
]
}
关键优化手段:
- 启用ASAR归档(减少文件数量)
- 使用UPX压缩二进制文件
- 移除devDependencies
4.2 自动更新实现
基于electron-updater的方案:
javascript复制autoUpdater.checkForUpdatesAndNotify({
title: '天气应用更新',
body: '版本 {version} 已准备好安装'
})
需在package.json中添加:
json复制"build": {
"publish": {
"provider": "github",
"repo": "your-repo-name"
}
}
5. 实际使用中的经验教训
-
时区陷阱:
- API返回的时间是UTC
- 必须用day.js转换本地时区:
javascript复制import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' dayjs.extend(utc) const localTime = dayjs.utc(apiTime).local() -
图标适配问题:
- 不同系统任务栏图标尺寸要求不同
- 需准备多种尺寸的ICO/PNG:
- Windows: 256x256, 64x64, 32x32
- macOS: 1024x1024@2x
-
用户位置获取:
- 优先尝试navigator.geolocation
- 备选方案:根据IP定位(精度较低)
这个项目最让我惊喜的是Electron的性能表现——即使在一台老旧的Surface Go上,应用启动时间也能控制在1.2秒以内。如果你也想开发类似工具,建议先从核心功能做起,避免过早陷入UI细节的泥潭。
