使用小程序网络API 的相关应用制作一款天气查询小程序。
一、实验目标
1、掌握服务器域名配置和临时服务器部署;2、掌握 wx.request 接口的用法。
二、实验步骤
列出实验的关键步骤、代码解析、截图。
注意:
本实验来自于周文洁老师的《微信小程序开发实战》第五章。主要介绍使用小程序 网络API 的相关应用制作一款天气查询小程序。 注意事项: 1、本实验中,需要使用和风天气API,需要注册用户,大家请自行阅读和风天气官 方文档:https://dev.qweather.com/docs/api/weather/weather-now/ 2、实验中需要的天气图片、utils.js 下载地址为: https://gaopursuit.oss-cn-beijing.aliyuncs.com/2022/demo2_file.zip 3、因为要向和风天气发送请求,如果保持登录状态将无法发送请求,切换为游客模式即可。
1.1 准备工作
1.1.1 API 密钥申请
介绍如何申请获得开源API的密钥。(以下内容使用和风天气API,网址为‘https://www.heweather.com/’)
1.1.1.1 注册账号
略
1.1.1.2 获取API密钥
点击左上角的“三” → “项目管理”
项目名称:任意
选择订阅:免费订阅
设置KEY:适用平台:Web API
key名称:任意
接下开就会获得密钥KEY(点击蓝色的查看即可获得密钥)
1.1.2 地区ID的获取
我们后面需要将地区的名称转化为ID方便查询,原因后面会揭晓
使用网址:https://geoapi.qweather.com(暂时忽略)
1.1.3 服务器域名配置
小程序与指定域名地址进行网络通信需要将该域名添加至白名单
1.1.3.1 登录 mp.weixin.qq.com
左侧导航栏中 “管理” → “开发管理”
下翻至服务器域名
点击修改,扫码身份验证后进入配置服务器域名
填写
https://devapi.qweather.com;https://geoapi.qweather.com;
注意
(1)可能网页会在最后自动补充“;”
(2)第一个网址是我们查询天气的API网址,第二个网址是将地址名称转化为地址ID的网址
1.2 项目创建
填写名称、目录、选择AppID,选择不使用云服务,模板选择JS基础模板
1.3 页面配置
1.3.1 创建页面文件
(1)将app.json中pages属性中的“pages/logs/logs"删除
1.3.2 删除和修改文件
(1)删除utils文件夹及其内部所有内容
(2)删除pages文件夹下的logs目录及其内部所有内容
(3)删除index.wxml和index.wxss中的所有代码
(4)删除index.js中的所有代码,并且输入关键词”page“找到第二个选项按回车键让其自动补全函数
(5)删除app.wxss中的所有代码
(6)删除app.js中的全部代码,并且输入关键词”app“找到第二个选项按回车键让其自动补全函数
1.3.3 创建其他文件
(1)下载天气图标
https://gaopursuit.oss-cn-beijing.aliyuncs.com/2022/demo2_file.zip
(2)直接解压到项目文件夹中(如我这里就是“2222”项目文件夹)
(解压后有三个文件夹都包含全套图标,选择一套喜欢的图标后要将其余两个删除,不然会文件过大报错)
(3)在文件操作系统中将第二级目录,即图标(.png)的父目录更名为 weather_icon
部分目录结构如下:
1.4 视图设计
1.4.1 导航栏设计
更改导航栏背景颜色和标题
修改文件:app.json
标题:今日天气
背景:#3883FA (蓝色)
app.json 代码:
{ "pages": [ "pages/index/index" ], "window": { "navigationBarTitleText": "今日天气", "navigationBarBackgroundColor": "#3883FA" } }
预览效果:
1.4.2 页面设计
页面包括页面整体和四个主要区域
-
页面整体:<view>组件,并定义class='container';
-
区域1:地区选择器,选择查询的省、市、区 <picker>
-
区域2:显示查询城市的温度和天气状态 <text>
-
区域3:显示查询城市的天气图标 <image>
-
区域4:分行显示其他天气信息,比如湿度、气压、风向等
区域4内单元行:4个<view>组件,代表四行 。定义class='bar'
区域4内单元格:每行3个<view>组件,代表有3列。定义class='box'
1.4.2.1 整体容器设计
在 pages/index/index.wxml 定义页面容器 <view>
<view class='container'> </view>
在 app.wxss 中设置容器样式(布局)
.container{ height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: space-around; }
目前只有单独的主页,并没有组件元素,还看不出来flex布局模型效果
1.4.2.2 区域1(地区选择器)设计
pages/index/index.wxml 使用<picker>组件实现地区选择器(目前默认为北京市)
<view class='container'> <!--区域 1:地区选择器--> <picker mode='region'> <view>北京市</view> </picker> </view>
1.4.2.3 区域2(文本)设计
pages/index/index.wxml 使用<text>组件显示当前城市温度和天气状况
<view class='container'> <!--区域 1:地区选择器--> <picker mode='region'> <view>北京市</view> </picker> <!--区域 2:单行天气信息--> <text>19℃晴</text> </view>
pages/index/index.wxss 中设计文本样式
text{ font-size: 80rpx; color:#3C5F81; }
1.4.2.4 区域3(天气图标)设计
pages/index/index.wxml 使用<image>组件展示图标
<view class='container'> <!--区域 1:地区选择器--> <picker mode='region'> <view>北京市</view> </picker> <!--区域 2:单行天气信息--> <text>19℃晴</text> <!--区域 3:天气图标--> <image src='/images/weather_icon/999.png' mode="widthFix"></image> </view>
pages/index/index.wxss 中设计图标样式
image{ width: 220rpx; }
1.4.2.5 区域4(多行其他天气信息)设计
pages/index/index.wxml 使用<image>组件展示图标
<view class='container'> <!--区域 1:地区选择器--> <picker mode='region'> <view>北京市</view> </picker> <!--区域 2:单行天气信息--> <text>19℃晴</text> <!--区域 3:天气图标--> <image src='/images/weather_icon/999.png' mode="widthFix"></image> <!--区域4:多行天气信息--> <view class='detail'> <view class='bar'> <view class='box'>温度</view> <view class='box'>气压</view> <view class='box'>能见度</view> </view> <view class='bar'> <view class='box'>0 %</view> <view class='box'>0 hpa</view> <view class='box'>0 km</view> </view> <view class='bar'> <view class='box'>风向</view> <view class='box'>风速</view> <view class='box'>风力</view> </view> <view class='bar'> <view class='box'>0 </view> <view class='box'>0 km/h</view> <view class='box'>0 级</view> </view> </view> </view>
pages/index/index.wxss 中设计图标样式
.detail{ width: 100%; display: flex; flex-direction: column; } .bar{ display: flex; flex-direction: row; margin: 20rpx 0; } .box{ width: 33.3%; text-align: center; }
效果图:
1.5 逻辑实现
1.5.1 更新省、市、区信息
(1)显示选择地区,添加自定义bindchange事件监听选项变化
pages/index/index.wxml
添加 bindchange='regionChange'
将 “北京市” 改为 “{{region}}”
<!--区域 1:地区选择器--> <picker mode='region'bindchange='regionChange'> <view>{{region}}</view> </picker>
(2)初始化region,region是一个含三个项目的数组
pages/index/index.js
Page({ /** * 页面的初始数据 */ data: { region:['安徽省','芜湖市','镜湖区'], }, regionChange: function(e) { this.setData({region: e.detail.value}); this.getWeather(); }, })
效果图:
1.5.2 获取实况天气数据
pages/index/index.js 中自定义getWeather获取实况天气数据
Page({ getWeather: function() { var that = this; // 第一步:获取 location ID wx.request({ url: "https://geoapi.qweather.com/v2/city/lookup",//将地区名称转化为地区ID data: { location: that.data.region[2], //精确到区 key: '和风天气密钥' //注意替换为之前申请的key }, success: function(res) { if (res.data && res.data.code === "200" && res.data.location.length > 0) { var locationId = res.data.location[0].id; // 获取第一个结果的 location ID // 第二步:使用 location ID 获取天气信息 wx.request({ url: "https://devapi.qweather.com/v7/weather/now", data: { location: locationId, // 使用获取到的 location ID key: '和风天气密钥' //注意替换为之前申请的key }, success: function(res) { console.log(res.data); // 打印天气信息 } }); } else { console.error("Location ID not found"); } } }); }, }) //更新天气 regionChange: function(e) { this.setData({region: e.detail.value}); this.getWeather(); }, onLoad: function (options) { this.getWeather(); },
编译后在Console控制台得到返回数据(格式如下图,重点在于有now中的天气信息)
pages/index/index.js
将上面中的打印返回信息 变为 更新显示的天气信息
Page({ getWeather: function() { ... success: function(res) { if (res.data && res.data.code === "200" && res.data.location.length > 0) { ... wx.request({ ... success: function(res) { that.setData({now:res.data.now}) //修改此处 } }); } ... } } }); }, })
1.5.3 更新页面天气信息
pages/index/index.wxml 将所有默认数据替换为返回结果now中对应数据
<view class='container'> <!--区域 1:地区选择器--> <picker mode='region'bindchange='regionChange'> <view>{{region}}</view> </picker> <!--区域 2:单行天气信息--> <text>{{now.temp}}℃{{now.text}}</text> <!--区域 3:天气图标--> <image src='/images/weather_icon/{{now.icon}}.png' mode="widthFix"></image> <!--区域4:多行天气信息--> <view class='detail'> <view class='bar'> <view class='box'>温度</view> <view class='box'>气压</view> <view class='box'>能见度</view> </view> <view class='bar'> <view class='box'>{{now.humidity}} %</view> <view class='box'>{{now.pressure}} hpa</view> <view class='box'>{{now.vis}} km</view> </view> <view class='bar'> <view class='box'>风向</view> <view class='box'>风速</view> <view class='box'>风力</view> </view> <view class='bar'> <view class='box'>{{now.windDir}} </view> <view class='box'>{{now.windSpeed}} km/h</view> <view class='box'>{{now.windScale}} 级</view> </view> </view> </view>
pages/index/index.js 设置now的默认值(初始值),在网速受限的条件下临时先显示这些默认值
部分代码:
data: { region:['安徽省','芜湖市','镜湖区'], now:{ temp:0, text:'未知', icon:'999', humidity:0, pressure:0, vis:0, windDir:0, windSpeed:0, windScale:0 } },
1.6 目录结构及完整代码
目录结构
pages/index/index.js
Page({ getWeather: function() { var that = this; // 第一步:获取 location ID wx.request({ url: "https://geoapi.qweather.com/v2/city/lookup", data: { location: that.data.region[2], key: '45625ad6a77c44c7a2d99977de9aef41' }, success: function(res) { if (res.data && res.data.code === "200" && res.data.location.length > 0) { var locationId = res.data.location[0].id; // 获取第一个结果的 location ID // 第二步:使用 location ID 获取天气信息 wx.request({ url: "https://devapi.qweather.com/v7/weather/now", data: { location: locationId, // 使用获取到的 location ID key: '45625ad6a77c44c7a2d99977de9aef41' }, success: function(res) { console.log(res.data); // 打印天气信息 that.setData({now:res.data.now}) } }); } else { console.error("Location ID not found"); } } }); }, /** * 页面的初始数据 */ data: { region:['安徽省','芜湖市','镜湖区'], now:{ temp:0, text:'未知', icon:'999', humidity:0, pressure:0, vis:0, windDir:0, windSpeed:0, windScale:0 } }, regionChange: function(e) { this.setData({region: e.detail.value}); this.getWeather(); }, onLoad: function (options) { this.getWeather(); }, })
pages/index/index.wxml
<view class='container'> <!--区域 1:地区选择器--> <picker mode='region'bindchange='regionChange'> <view>{{region}}</view> </picker> <!--区域 2:单行天气信息--> <text>{{now.temp}}℃{{now.text}}</text> <!--区域 3:天气图标--> <image src='/images/weather_icon/{{now.icon}}.png' mode="widthFix"></image> <!--区域4:多行天气信息--> <view class='detail'> <view class='bar'> <view class='box'>温度</view> <view class='box'>气压</view> <view class='box'>能见度</view> </view> <view class='bar'> <view class='box'>{{now.humidity}} %</view> <view class='box'>{{now.pressure}} hpa</view> <view class='box'>{{now.vis}} km</view> </view> <view class='bar'> <view class='box'>风向</view> <view class='box'>风速</view> <view class='box'>风力</view> </view> <view class='bar'> <view class='box'>{{now.windDir}} </view> <view class='box'>{{now.windSpeed}} km/h</view> <view class='box'>{{now.windScale}} 级</view> </view> </view> </view>
pages/index/index.wxss
text{ font-size: 80rpx; color:#3C5F81; } image{ width: 220rpx; } .detail{ width: 100%; display: flex; flex-direction: column; } .bar{ display: flex; flex-direction: row; margin: 20rpx 0; } .box{ width: 33.3%; text-align: center; }
app.json
{ "pages": [ "pages/index/index" ], "window": { "navigationBarTitleText": "今日天气", "navigationBarBackgroundColor": "#3883FA" }, "style": "v2", "componentFramework": "glass-easel", "sitemapLocation": "sitemap.json", "lazyCodeLoading": "requiredComponents" }
app.wxss
.container{ height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: space-around; }
三、程序运行结果
列出程序的最终运行结果及截图。
默认界面:
选择界面: 查询结构界面:
四、问题总结与体会
1. 实验过程中遇到的问题
在实验过程中,我遇到了以下问题:
-
和风天气API的使用问题:由于实验需要使用和风天气API获取天气数据,初次使用时对于API的调用方法不熟悉,尤其是在如何传递正确的参数和解析返回数据上遇到了困难。
-
微信小程序域名配置问题:配置服务器域名时,遇到域名验证失败的问题。经过查找资料,发现是由于域名未通过HTTPS验证,导致微信小程序不接受请求。
-
页面更新的逻辑实现:在编写获取天气数据并更新页面显示的代码时,遇到了异步请求数据的处理问题,导致页面刷新不及时。
2. 问题的解决方法
-
学习API文档:仔细阅读和风天气API的官方文档,理解API的使用方法和参数的意义。通过调试工具逐步验证传入参数的正确性,最终成功获取并解析天气数据。
-
域名配置问题的解决:通过将临时服务器切换至支持HTTPS的域名,完成了域名的配置,并成功与微信小程序对接。
-
页面更新问题的解决:通过将异步请求的回调函数与页面刷新逻辑结合,确保在数据获取成功后立即更新页面,保证了用户体验的流畅性。
3. 收获与体会
-
API调用的经验:通过本次实验,我对如何使用第三方API获取数据有了更深入的理解,特别是在处理异步请求和数据解析方面,积累了宝贵的经验。
-
微信小程序开发技巧:通过这个实验,熟悉了微信小程序开发的基本流程,包括项目创建、页面配置、视图设计以及逻辑实现,为后续的开发奠定了基础。
4. 对课程安排的建议
建议在课程中增加更多关于常见问题的解决方案讨论,如API调用中的常见错误、异步数据处理技巧等,这样能够帮助学生更好地应对实际开发中的挑战。此外,可以增加实验报告的交流环节,让学生分享他们在实验中的心得体会和遇到的困难,共同提高开发技能。