简介:一份提供完整项目文件和效果截图的微信小程序天气预报源码,适合小程序初学者、前端开发者以及正在做课程设计或毕业设计的学生使用,能够帮助读者直观理解天气类小程序的页面组织、样式设计与数据交互流程。rar压缩包共收录47个文件,容量约928KB,内部包含15张png效果截图和4张jpg辅助图片,方便还原界面细节;8个wxml文件定义页面结构,6个wxss文件控制界面样式,8个js文件负责业务逻辑与事件处理,4个json文件完成应用与页面配置,另有2个ts文件用于类型辅助,整体目录明晰,导入微信开发者工具即可对照学习。已有1390人学习下载,说明该源码在小程序学习群体中具有一定参考价值。借助这份资源,可以省去从零搭建项目的时间,直接研读代码实现,掌握小程序项目结构与常见开发技巧,非常适合作为实战训练模板。
1. 为什么一份带截图的天气预报源码值得拆开看
做微信小程序开发的人,十有八九会卡在同一个地方:不是不会写wx.request,而是不知道一个完整的、能过审的、UI 不辣眼的小程序长什么样。网上能找到的天气类 demo 要么只有一两个页面,要么跑起来全是样式错位,更别提把定位、刷新、多日预报、错误兜底都串起来。这套带截图的微信小程序天气预报源码,正好补上这个缺口——压缩包里每个页面的运行效果都有对应 PNG,你能直接对照截图看代码,不用猜哪个组件长什么样。源码结构不复杂,逻辑层用的是原生wxAPI,界面层走的是 flex + rpx 那套经典写法,适合刚入门想抄作业的人,也适合需要快速搭一个天气模块塞进自己毕设或外包项目里的从业者。更重要的是,这套包可以在微信开发者工具里直接打开,改掉 appid、换掉请求头就能跑,省掉从零搭建的半天时间。
2. 目录拆解:从 RAR 到开发者工具,先搞懂这份源码的骨架
拿到微信小程序源码(含截图)天气预报.rar后,先别急着解压双击。常见做法是解压到英文路径下,因为微信开发者工具对中文路径的支持虽然没问题,但某些依赖miniprogram_npm的插件在中文路径下偶尔会报模块找不到,纯英文路径能省一个变量。
2.1 压缩包内容物清单
解压后你会看到这样的目录结构(截图文件名weather 1.png、weather2、wether1 2.png、3.png对应不同页面状态):
weather/ ├── app.js ├── app.json ├── app.wxss ├── pages/ │ ├── index/ │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ └── logs/ // 部分版本会有 ├── utils/ │ └── util.js ├── images/ // 天气图标等静态资源 └── project.config.json这份源码属于典型的原生小程序结构,没有用 TypeScript 也没有用第三方 UI 库,所以对刚接触小程序的人特别友好。app.js里做全局数据和启动逻辑,app.json注册页面和窗口样式,真正的页面渲染逻辑全在pages/index下。截图中展示的天气卡片、未来预报列表、刷新按钮,都对应index.wxml里的某个节点块,一一对照截图就能快速定位要改的位置。
2.2 用开发者工具跑起来的三个步骤
在微信开发者工具里选择「导入项目」,目录指向解压后的weather文件夹。AppID 可以选测试号,也可以用你自己的小程序 AppID,但注意天气接口如果用了自有域名,需要在「详情 → 本地设置」里勾选「不校验合法域名」,否则wx.request会被拦下来。
# 解压 unzip 微信小程序源码(含截图)天气预报.rar -d ./weather_project # 用微信开发者工具打开 weather_project/weather 目录即可这里有个容易踩的坑:如果解压后project.config.json里的miniprogramRoot字段指向了子目录,导入时要选那个子目录而不是外层文件夹。判断方法很简单,看哪一级目录下直接躺着app.json,就导入哪一级。源码里如果project.config.json里配置了"compileType": "miniprogram",那基本没有大问题,导入后会自动编译。
2.3 app.json 里那些值得改的配置
app.json是理解整套源码行为的关键入口。打开它后你会看到pages数组、window对象,可能还有permission字段。这套源码里permission字段管理的是用户授权,尤其是scope.userLocation,因为天气功能必须拿到地理位置才能查当地天气。
{ "pages": ["pages/index/index"], "permission": { "scope.userLocation": { "desc": "你的位置信息将用于获取当地天气" } }, "window": { "navigationBarBackgroundColor": "#4A90D9", "navigationBarTitleText": "天气预报" } }这里desc不能写得含糊,微信审核时如果发现定位用途描述和实际功能不符,会被驳回。源码里默认写的是「你的位置信息将用于获取当地天气」,如果你改成会议打卡之类的小程序,这里的说明一定要同步改,否则审核人员会拿「用途不一致」驳回你。
3. 天气 API 接入与数据绑定实战
这份源码的核心逻辑集中在index.js里,主要做四件事:获取定位、请求天气接口、解析返回数据、把数据绑定到视图。理解这条链路,你就知道怎么把免费天气接口换成自己的私有接口。
3.1 定位与请求的串联方式
主流做法是先用wx.getLocation拿到经纬度,再拼到天气 API 的 URL 上。源码里大概率用的和下面这段结构类似:
Page({ data: { weatherData: null, cityName: "正在定位...", loading: true }, onLoad() { this.fetchWeatherByLocation(); }, fetchWeatherByLocation() { wx.getLocation({ type: "gcj02", success: (res) => { const { latitude, longitude } = res; this.requestWeather(latitude, longitude); }, fail: () => { // 用户拒绝授权时,给一个默认城市兜底 this.requestWeather(39.9042, 116.4074); } }); }, requestWeather(lat, lon) { wx.request({ // 以和风天气为例,实际源码可能使用其他服务商 url: `https://your-weather-api.com/now?location=${lon},${lat}`, header: { "Content-Type": "application/json" }, success: (res) => { if (res.statusCode === 200 && res.data) { this.setData({ weatherData: res.data, loading: false }); } } }); } });这段代码里有两个细节:type: "gcj02"是国内标准坐标系,用于展示在腾讯地图上没问题;直接用通用坐标可能造成几十到几百米的偏移,吹风风向和温度数据不受影响,但如果你的天气页还要叠加地图,就必须用gcj02。另一个细节是fail回调里的兜底城市坐标,这个设计非常实用——小程序的授权弹窗被拒绝后,success不会触发,如果没兜底页面会永远卡在 loading 状态。
3.2 返回数据的 View 层绑定
天气接口返回的 JSON 结构一般是嵌套的,比如res.data.now.temp表示当前温度,res.data.daily是数组存未来几天预报。源码index.js的setData里会做一次数据整形,把嵌套结构拍平,方便 WXML 绑定:
// 数据整形示例 const now = res.data.now; const daily = res.data.daily || []; this.setData({ temperature: now.temp, weatherText: now.text, dailyForecast: daily.map((item) => ({ date: item.fxDate, tempMax: item.tempMax, tempMin: item.tempMin })) });对应在index.wxml中就是:
<view class="current"> <text class="temp">{{temperature}}°</text> <text class="desc">{{weatherText}}</text> </view> <view class="daily" wx:for="{{dailyForecast}}" wx:key="date"> <text>{{item.date}}</text> <text>{{item.tempMin}}° ~ {{item.tempMax}}°</text> </view>这里一个值得注意的坑是:wx:for一定要配wx:key,否则数据更新时视图层会全量重渲染。特别是天气预报这种每隔几分钟就要刷新一次的场景,没有wx:key会导致页面明显卡顿,截图里看起来流畅的滑动效果会荡然无存。
3.3 接口选择与请求头注意点
源码里用的具体天气接口服务商如果是旧版免费接口,现在大概率已经不能用了。很多免费天气 API 换了域名,要求请求头带X-User-Key或Authorization,直接在wx.request的header里加就行。还有的接口必须走 HTTPS,如果你在开发者工具里勾了「不校验合法域名」,本地能看到数据,但真机预览时会被拦下。所以上线前一定要去小程序后台把天气 API 的域名加到 request 合法域名里,而且要主动检查接口日志里有没有request:fail报错,最常见的不是密钥过期,而是二级域名带了端口号,小程序合法域名不允许带端口。
4. 定位授权、UI 适配与常见坑位排查
这一章聊的是把源码真正跑通、跑顺的过程中,90% 的人会撞上的墙。如果你在开发者工具里一切正常,但在真机上数据死活不出来,或者出来以后 UI 直接崩了,基本都逃不开下面这几类问题。
4.1 授权弹窗的时序问题
源码里wx.getLocation写在onLoad里,这在小程序生态里是一个有争议的写法。原因是onLoad触发时,页面组件还没完全布局,这时候弹出授权框,用户点击允许后再回调setData,部分安卓机型的渲染会闪烁一下。更稳的方案是把授权逻辑收敛到一个按钮事件或wx.authorize前置判断里:
wx.authorize({ scope: "scope.userLocation", success() { // 已授权,直接定位 wx.getLocation({ type: "gcj02" }); }, fail() { // 未授权,引导用户去设置页打开 wx.showModal({ title: "需要位置权限", content: "请在设置中打开位置权限以获取本地天气", success(res) { if (res.confirm) { wx.openSetting(); } } }); } });这段代码在源码基础上做了防御性增强。你会发现,真正上线的天气小程序几乎都不会在onLoad里直接硬求授权,而是先渲染一个「点击获取天气」的占位页,用户点了再触发授权,这样转化率更高,也符合微信的审核规范。如果你拿这份源码做毕业设计,建议把授权触发点改成按钮,演示时更有「交互感」,答辩老师也更好提问题。
4.2 rpx 单位与刘海屏适配
天气预报页面顶部通常有一块大数字温度展示,适配不好时,在 iPhone 13 Pro Max 或小米 Civi 这种屏幕比例特殊的机型上会左右溢出。这套源码的wxss里用的是rpx,它在不同宽度设备上会自动换算,但有一类问题它管不了——状态栏高度和胶囊按钮的位置。如果你的页面自定义了导航栏,必须在app.js或页面onLoad里获取状态栏高度:
wx.getWindowInfo({ success(res) { this.setData({ statusBarHeight: res.statusBarHeight, menuButton: wx.getMenuButtonBoundingClientRect() }); } });然后在 WXML 里给顶部容器加 padding 或 margin:
<view class="header" style="padding-top: {{statusBarHeight}}px;"> <text>{{cityName}}</text> </view>如果不处理这一步,在刘海屏上「城市名」会被摄像头挖孔遮住,截图里看着正常是因为截图设备可能没有刘海。源码里如果没有这段逻辑,你在真机调试时一定要补上,不然交出去的照片会很掉价。
4.3 数据刷新与缓存策略
天气预报本身对实时性要求没那么高,频繁请求反而容易被接口限流。源码里如果只在onLoad拉一次数据,那用户在页面上停留半小时温度就不会更新,体验和截图里定格的画面没什么区别。我一般会在源码基础上加一个定时器,半小时拉一次,并且把上次请求的数据缓存到wx.setStorageSync里:
const CACHE_KEY = "weather_cache"; onLoad() { const cache = wx.getStorageSync(CACHE_KEY); if (cache && Date.now() - cache.timestamp < 1800000) { this.setData({ temperature: cache.temperature, dailyForecast: cache.dailyForecast }); return; } this.fetchWeatherByLocation(); }, fetchWeatherByLocation() { // 原有逻辑,成功后同步写缓存 const cacheData = { temperature: now.temp, dailyForecast: daily, timestamp: Date.now() }; wx.setStorageSync(CACHE_KEY, cacheData); }这里有个容易被忽略的点:缓存必须带时间戳,否则永远是旧数据。而且setStorageSync不要放在success回调的嵌套最深处,容易遗漏。你甚至可以把这个逻辑抽到utils里,给页面里的其他数据也用上,源码里没抽也没关系,自己手动挪一下就好。
4.4 常见报错对照表
| 报错信息 | 原因 | 解决方法 |
|---|---|---|
request:fail url not in domain list | 请求域名没配置 | 在 mp 后台添加合法域名,或本地勾选不校验 |
getLocation:fail the api need to be declared in ... | app.json缺permission声明 | 参考前一章的permission字段补上 |
TypeError: Cannot read property 'temp' of undefined | 接口返回结构变化或请求失败 | 在success里先打印res.data,确认字段路径 |
thirdScriptError后面跟着一长串 | 常见于代码里用了 ES6+ 语法而基础库版本过低 | project.config.json里调低或调高基础库版本到 2.20+ |
| 截图和实际运行样式不一致 | 截图所用设备分辨率不同,或用了px写死 | 全局搜索px:,把关键布局改成rpx |
最后那个「截图和实际样式不一致」非常值得展开。源码里附带截图的本质是给购买或下载者做预期管理,但很多截图是在开发者工具模拟器里截的,模拟器默认 iPhone X 尺寸,真机跑到安卓 21:9 的屏幕上,宽度变化超过 20% 时px写死的元素就会溢出。排查方法很简单:把开发者工具切到 iPhone SE / 安卓机型两种预设分别跑一遍,截图对照,哪里错位一眼可见。
5. 再进一步:反编译对照、uni-app 迁移与加载页优化技巧
拿到一份能跑的源码不算结束,真正的技术提升在于能对这份源码做二次加工。最后这一章给三个具体方向,每一个都对应实际工作里经常被问到的问题。
5.1 用反编译工具验证你下载的源码是否完整
网上流传的很多所谓「微信小程序源码」会被去掉.wxapkg包或只保留核心页面,导致导入后空白。你可能也遇到过这种情况——压缩包里只有app.js但没有pages/index/index.js,这种源码基本废了。验证方法除了看目录结构,还可以直接反编译其它已上线小程序做对照练习。工具常见的有wxappUnpacker或基于 Node 的unveilr,用法如下:
npx unveilr -i 目标.wxapkg -o ./output反编译出来的代码虽然是编译后的,但wxml和wxss基本是完整的,可以从中学到人家是怎么处理加载动画、骨架屏以及天气图标切换的。注意反编译仅用于个人学习研究,不要拿去直接发布或商用,小程序社区对这块查得越来越严,尤其是带原创 UI 设计的小程序,截图里的图标和配色都可能涉及版权问题。
5.2 把原生源码迁到 uni-app 的省力路径
热搜里大量人在搜「uniapp 微信小程序」,说明很多人已经在用 Vue 语法跨端开发。如果你想把这份原生小程序源码迁到uni-app,有一个相对省力的办法:保留原生渲染能力,只把业务逻辑重写。
uni-app支持在pages.json里直接配置原生小程序插件,也可以通过wx全局对象调用微信原生 API。实际操作中,你只需要关心三处改动:
// pages.json 对应原本 app.json 的 pages/window 配置 { "pages": [{ "path": "pages/index/index", "style": { "navigationBarTitleText": "天气预报", "enablePullDownRefresh": true } }], "globalStyle": { "navigationBarBackgroundColor": "#4A90D9" } }对应 Vue 页面的脚本部分,onLoad生命周期从Page()改成onLoad(options),setData直接改成this.temperature = now.temp,因为uni-app是数据响应式的。这里有个坑:uni-app里如果要使用wx.getLocation,需要先安装uni-app的定位模块,或者直接调用uni.getLocation。如果你迁移的目标是 H5 + 小程序双端,建议用uni.getLocation,因为它能自动处理不同端差异。
5.3 修改刚进入的加载页面,让首屏体验接近商业级
热搜词里有一条「修改刚进入的加载页面」,这在天气小程序里特别典型——因为定位是异步的,没拿到坐标之前页面会出现一段白屏。源码如果直接显示「正在定位…」文字,不够细腻。商业做法是在wx.request发出前先渲染一套骨架屏,等数据回来后替换成真实内容。
<!-- 骨架屏:与真实布局结构一致,但内容用灰色色块填充 --> <view class="skeleton" wx:if="{{loading}}"> <view class="skeleton-temp"></view> <view class="skeleton-daily"> <view class="skeleton-row" wx:for="{{[1,2,3]}}" wx:key="*this"></view> </view> </view> <view class="real-content" wx:else> <!-- 真实天气内容 --> </view>配合wxss让那块skeleton-temp做一个从左到右的浅色渐变动画,视觉上就会有一个「数据正在加载」的反馈。这类骨架屏样式可以直接用animation属性实现,不用引入额外组件库:
.skeleton-temp { width: 200rpx; height: 200rpx; border-radius: 50%; background: linear-gradient(90deg, #eee 25%, #f5f5f5 37%, #eee 63%); background-size: 400% 100%; animation: skeleton-loading 1.4s ease infinite; } @keyframes skeleton-loading { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }注意wx:if和wx:else之间的切换要在setData里一律改为数据驱动,比如loading这个布尔值,而不是用wx.hideLoading去藏弹窗。很多新手在这里会把 loading 状态写死,导致页面卡在骨架屏出不来。排查这种问题的最快办法是在开发者工具的 AppData 面板里看loading字段有没有由true变false,如果变了但 UI 还卡着,那就是wxss的优先级覆盖问题;如果没变,就去查requestWeather的 fail 回调是不是被吞了。把错误信息打印出来,比对着截图猜有效得多。
本文还有配套的精品资源,点击获取