第5章小程序网络API·天气查询 本章主要介绍使用小程序网络API的相关应用制作一款天气查询小程序。  掌握服务器域名配置和临时服务器部署;  掌握wx.request接口的用法。 5.1准备工作 5.1.1API密钥申请 视频讲解 本小节主要介绍如何申请获得开源API的密钥。这里选择了可以提供全球气象数据服务接口的和风天气API,其官方网址为 “https://www.heweather.com/”(如图51所示)。 图51“和风天气”官方主页(访问时间: 2018.10.27 10:26) 用户选择“免费用户”类型,使用邮箱进行注册并激活后可以获取三天之内全球各地区的实时天气,免费接口调用流量为1000次/天、频率为200次/分钟,该数据基本上可以满足读者的开发学习需求。 注册完毕之后可以访问“https://console.heweather.com/my/service”来查看账号信息,用户登录后即可看到开发者申请到的个人认证key,如图52所示。 图52个人认证key查询页面(访问时间: 2018.10.27 10:27) 开发者需记录上述页面中的个人认证key,该信息在小程序发出网络请求时会作为身份识别的标识一并发送给和风天气的第三方服务器。至此,开源API的密钥申请就已经顺利完成,读者可以进行5.1.2节的学习,了解如何调用API获取气象数据。 视频讲解 5.1.2API调用方法 目前免费用户可以调用的最新版接口地址为“https://freeapi.heweather.com/s6/”,其服务器节点在中国境内。该接口地址后面追加不同的关键词将获取不同种类的气象数据信息,例如alarm为天气自然灾害预警。读者可以访问官方文档(https://dev.heweather.com/docs/api/)了解各类关键词的使用方法。 本示例将选用关键词weather进行实况天气数据的获取。实况天气即为当前时间点的天气状况以及温/湿/风/压等气象指数,具体包含体感温度、实测温度、天气状况、风力、风速、风向、相对湿度、大气压强、降水量、能见度等。目前该接口允许查询的城市覆盖范围为全球任意一个城市。 基于关键词weather的接口具有两个必填参数和两个可选参数,如表51所示。 表51weather接口参数一览表 参 数 名 称参 数 类 型解释 city必填参数用于规定需要查询的城市,可以填入城市名称(国内城市填中文或拼音均可)、城市ID、IP地址或经纬度。 例如: city=北京、city=beijing(城市名称) city=CN101010100(城市ID) city=60.194.130.1(IP地址) city=120.343,36.088(经纬度) key必填参数需要填入用户的个人认证key字符串。接口将通过该数据判断是否为授权用户,并可以进一步判断是否为付费用户。 例如: key=123abc456dfg lang可选参数用于指定数据的语言版本,不添加lang参数则默认为简体中文。 例如: lang=en 需要注意的是,国内某些特定数据(例如生活指数、空气质量等)不支持多语言版 unit可选参数单位选择,公制(m)或英制(i),默认为公制单位。 例如: unit=i 详见表52“度量衡单位一览表” 其中与unit参数相关的公制和英制单位对比如表52所示。 表52度量衡单位一览表 数据项公 制 单 位英 制 单 位 温度摄氏度: ℃华氏度: ℉ 风速公里/小时: km/h英里/小时: mile/h 能见度公里: km英里: mile 大气压强百帕: hPa百帕: hPa 降水量毫米: mm毫米: mm PM2.5微克/立方米: μg/m3微克/立方米: μg/m3 PM10微克/立方米: μg/m3微克/立方米: μg/m3 O3微克/立方米: μg/m3微克/立方米: μg/m3 SO2微克/立方米: μg/m3微克/立方米: μg/m3 CO毫克/立方米: mg/m3毫克/立方米: mg/m3 NO2微克/立方米: μg/m3微克/立方米: μg/m3 注意: 部分数据项无论选择何种单位均会使用公制单位。 免费用户调用接口的常见语法格式如下: https://free-api.heweather.com/s6/weather/now?[parameters] 其中[parameters]需要替换成使用到的参数,多个参数之间使用&符号隔开。 例如,使用拼音查询上海市天气数据的写法如下: https://free-api.heweather.com/s6/weather/now?location=shanghai&key=1234abcd 注意,其中key的值1234abcd为随机填写的内容,请在实际开发中将其替换为真实的个人认证key,否则接口将无法获取数据。 用户可以直接将这段地址输入到浏览器的地址栏中测试数据返回结果,如图53所示。 图53免费天气查询接口返回结果页面(访问时间: 2018.10.27 10:59) 由该图可知,指定城市的天气数据返回结果是JSON数据格式的文本内容,其中包含的数据是以“名称:值”的形式存放。 为方便用户查看,将图53返回的数据内容整理格式如下: { "HeWeather6":[ { "basic":{ "cid":"CN101020100", "location":"上海", "parent_city":"上海", "admin_area":"上海", "cnty":"中国", "lat":"31.23170662", "lon":"121.47264099", "tz":"+8.00" }, "update":{ "loc":"2018-10-27 10:45", "utc":"2018-10-27 02:45" }, "status":"ok", "now":{ "cloud":"0", "cond_code":"100", "cond_txt":"晴", "fl":"17", "hum":"19", "pcpn":"0.0", "pres":"1024", "tmp":"19", "vis":"10", "wind_deg":"315", "wind_dir":"西北风", "wind_sc":"1", "wind_spd":"4" } } ] } 返回的字段说明如表53所示。 表53实况天气返回字段说明 basic: 基础信息 参数描述示例值 location地区/城市名称海淀 cid地区/城市IDCN101080402 lat地区/城市纬度39.956074 lon地区/城市经度116.310316 parent_city该地区/城市的上级城市北京 admin_area该地区/城市所属行政区域北京 cnty该地区/城市所属国家名称中国 tz该地区/城市所在时区8 update: 接口更新时间 参数描述示例值 loc当地时间,24小时制,格式为yyyyMMdd HH:mm2017/10/25 12:34 utcUTC时间,24小时制,格式为yyyyMMdd HH:mm2017/10/25 4:34 now: 实况天气 参数描述示例值 fl体感温度,默认单位为摄氏度23 tmp温度,默认单位为摄氏度21 cond_code实况天气状况代码100 cond_txt实况天气状况描述晴 续表 参数描述示例值 wind_deg风向360角度305 wind_dir风向西北 wind_sc风力3 wind_spd风速,公里/小时15 hum相对湿度40 pcpn降水量0 pres大气压强1020 vis能见度,默认单位为公里10 cloud云量23 status: 接口状态 参数描述示例值 status接口状态,具体含义请参考表54“接口状态码及错误码说明”ok 其中参数status的状态码及错误码说明如表54所示。 表54接口状态码及错误码说明 代码说明 ok数据正常 invalid key错误的key,请检查key是否输入以及是否输入有误 unknown location未知或错误城市/地区 no data for this location该城市/地区没有所请求的数据 no more requests超过访问次数,需要等到当月最后一天24点(免费用户为当天24点)后进行访问次数的重置或升级访问量 param invalid参数错误,请检查传递的参数是否正确 too fast超过限定的QPM,请参考QPM说明 dead无响应或超时,接口服务异常请联系产品开发商 permission denied无访问权限,没有购买所访问的这部分服务 sign error签名错误,请参考签名算法 如果接口无法正确地获取数据,可以根据状态码对比该表查询原因。 用户可以根据指定的名称找到对应的数据值,例如在实况天气数据(now)中可以查到当前城市的温度,对应的字段节选如下: "tmp":"19" 上述代码表示当前城市的温度为19℃。 视频讲解 5.1.3服务器域名配置 每一个小程序在与指定域名地址进行网络通信前都必须将该域名地址添加到管理员后台白名单中,因此本示例需要对域名地址 “https://freeapi.heweather.com”进行服务器配置。 小程序开发者登录mp.weixin.qq.com进入管理员后台,单击“设置”按钮,切换至“开发设置”面板,在“服务器域名”栏中可以添加或修改需要进行网络通信的服务器域名地址,如图54所示。 图54服务器域名配置 将当前需要使用的接口添加到“request合法域名”中,配置完成后再登录小程序开发工具就 允许小程序与指定的服务器域名地址之间的网络通信了,注意每个月只可以申请修改5次服务器域名配置。 5.2项目创建 视频讲解 本项目创建选择空白文件夹weatherDemo,效果如图55所示。 图55小程序项目填写效果示意图 单击“新建”按钮完成项目创建,然后准备手动创建页面配置文件。 5.3页面配置 5.3.1创建页面文件 视频讲解 项目创建完毕后,在根目录中会生成文件夹pages用于存放页面文件。一般来说首页默认命名为index,表示小程序运行的第一个页面; 其他页面名称可以自定义。本项目只需要保留首页(index)即可。 具体操作如下: (1) 将app.json文件内pages属性中的“pages/logs/logs”删除,并删除上一行末尾的逗号。 (2) 按快捷键Ctrl+S保存当前修改。 5.3.2删除和修改文件 具体操作如下: (1) 删除utils文件夹及其内部所有内容。 (2) 删除pages文件夹下的logs目录及其内部所有内容。 (3) 删除index.wxml和index.wxss中的全部代码。 (4) 删除index.js中的全部代码,并且输入关键词page找到第二个选项按回车键让其自动补全函数(如图56所示)。 图56输入关键词创建Page函数 (5) 删除app.wxss中的全部代码。 (6) 删除app.js中的全部代码,并且输入关键词app找到第一个选项按回车键让其自动补全函数(如图57所示)。 图57输入关键词创建App函数 5.3.3创建其他文件 接下来创建其他自定义文件,本项目还需要一个文件夹用于存放天气图标素材。文件夹名称由开发者自定义(例如images),单击目录结构左上角的+号创建文件夹并命名为images。 本项目用到的图标素材共计75个,均来源于和风天气官网,图标素材展示如图58所示。 图58天气图标素材展示 其中图标文件名为对应的天气代码,扩展名均为.png。需要注意的是,部分图标文件名带有字母n,表示夜间天气图标,例如100n.png。 右击目录结构中的images文件夹,选择“硬盘打开”,在该文件夹中新建二级目录weather_icon,然后将图标文件全部复制、粘贴进去。完成后的目录结构如图59所示。 图59页面文件创建完成 此时文件配置就全部完成,5.4节将正式进行页面布局和样式设计。 5.4视图设计 5.4.1导航栏设计 视频讲解 小程序默认导航栏是黑底白字的效果,因此需要在app.json中自定义导航栏标题和背景颜色。更改后的app.json文件代码如下: 1.{ 2."pages": [ 3."pages/index/index" 4.], 5."window": { 6."navigationBarBackgroundColor": "#3883FA", 7."navigationBarTitleText": "今日天气" 8.} 9.} 图510自定义导航栏效果 上述代码可以更改所有页面的导航栏标题文本为“今日天气”、背景颜色为蓝色(#3883FA)。预览效果如图510所示。 视频讲解 5.4.2页面设计 页面上主要包含4个区域,具体内容解释如下。  区域1: 地区选择器,用户可以自行选择查询的省、市、区;  区域2: 显示当前城市的温度和天气状态的文字说明;  区域3: 显示当前城市的天气图标;  区域4: 分多行显示其他天气信息,例如湿度、气压、能见度和风向等。 注意,面板之间需要有一定的间隔距离,设计图如图511所示。 计划使用如下组件。  页面整体: 组件,并定义class='container';  区域1: 组件;  区域2: 组件;  区域3: 组件;  区域4: 组件,并定义class='detail';  区域4内单元行: 4个组件,并定义class= 'bar';  区域4内单元格: 每行3个组件,并定义class='box'。 1 整体容器设计 首先定义页面容器(),WXML(pages/index/index.wxml)代码片段如下: 1. 2. 在app.wxss中设置容器样式,代码片段如下: 1./*背景容器样式*/ 2..container{ 3.height: 100vh;/*高度为100视窗,写成100%无效*/ 4.display: flex; /*flex布局模型*/ 5.flex-direction: column; /*垂直布局*/ 6.align-items: center;/*水平方向居中*/ 7.justify-content:space-around;/*调整间距*/ 8.} 当前效果如图512所示。 图511页面设计图 图512页面预览效果 由于还没有添加组件元素,所以尚看不出来flex布局模型效果。 2 区域1(地区选择器)设计 区域1需要使用组件来实现一个地区选择器,用户点击可切换选择其他城市。 WXML(pages/index/index.wxml)代码片段修改如下: 1. 2. 3. 4.北京市 5. 6. 组件内部是开发者任意填写的一个城市名称,当前效果如图513所示。 图513区域1预览效果 由图可见,点击城市名称时会从底部弹出控件,用户可以进行省、市、区的选择。 3 区域2(文本)设计 区域2需要使用组件实现一个单行天气信息,包括当前城市的温度和天气状况。 WXML(pages/index/index.wxml)代码片段修改如下: 1. 2. 3.… 4. 5.19℃晴 6. WXSS(pages/index/index.wxss)代码片段如下: 1./*文本样式*/ 2.text{ 3.font-size: 80rpx; 4.color:#3C5F81; 5.} 当前效果如图514所示。 当前显示的文本内容由开发者自定义,待查询到实际数据后将动态更新文本内容。 4 区域3(天气图标)设计 区域3需要使用组件展示当前城市的天气图标。 WXML(pages/index/index.wxml)代码片段修改如下: 1. 2. 3.… 4. 5.… 6. 7. 8. WXSS(pages/index/index.wxss)代码片段如下: 1./*图标样式*/ 2.image{ 3.width: 220rpx; 4.} 当前效果如图515所示。 图514区域2预览效果 图515区域3预览效果 “N/A”表示天气状况为“未知”,待查询到实况数据后将动态更新图标内容。 5 区域4(多行天气信息)设计 区域4需要使用组件展示多行天气信息。 WXML(pages/index/index.wxml)代码片段修改如下: 1. 2. 3.… 4. 5.… 6. 7.… 8. 9. 10. 11.湿度 12.气压 13.能见度 14. 15. 16.0 % 17.0 hPa 18.0 km 19. 20. 21.风向 22.风速 23.风力 24. 25. 26.0 27.0 km/h 28.0 级 29. 30. 31. 图516区域4预览效果 WXSS(pages/index/index.wxss)代码片段如下: 1./*区域4整体样式*/ 2..detail{ 3.width: 100%; 4.display: flex; 5.flex-direction: column; 6.} 7./*区域4单元行样式*/ 8..bar{ 9.display: flex; 10.flex-direction: row; 11.margin: 20rpx 0; 12.} 13./*区域4单元格样式*/ 14..box{ 15.width: 33.3%; 16.text-align: center; 17.} 当前效果如图516所示。 当前为开发者自定义数据,待查询到实况数据后将动态更新区域4的内容。此时页面设计就全部完成了,接下来需要进行逻辑实现。 5.5逻辑实现 5.5.1更新省、市、区信息 视频讲解 首先修改组件中的“北京市”为{{region}},然后为组件追加自定义bindchange事件,用于监听选项变化。 WXML(pages/index/index.wxml)代码片段修改如下: 1. 2. 3. 4.{{region}} 5. 6. 由于地区选择器的返回结果是数组的形式,所以在JS文件的data中定义region为包含了省、市、区3个项目的数组,初始城市信息由开发者自定义。 JS(pages/index/index.js)代码片段修改如下: 1.Page({ 2./** 3.* 页面的初始数据 4.*/ 5.data: { 6.region:['安徽省','芜湖市','镜湖区'] 7.}, 8./** 9.* 更新省、市、区信息 10.*/ 11.regionChange: function(e) { 12.this.setData({region: e.detail.value}); 13.}, 14.}) 运行效果如图517所示。 图517更新省、市、区信息前后 由图可见,当前已经可以自行切换到国内任意省、市、区。 视频讲解 5.5.2获取实况天气数据 在JS文件中使用自定义函数getWeather进行实况天气数据的获取。由于非直辖市无法查询到具体的区,所以后续的天气查询以城市作为查询依据。 JS(pages/index/index.js)代码片段修改如下: 1.Page({ 2./** 3.* 获取实况天气数据 4.*/ 5.getWeather: function() { 6.var that = this; 7.wx.request({ 8.url: 'https://free-api.heweather.com/s6/weather/now', 9.data:{ 10.location:that.data.region[1], 11.key:'请填入开发者申请的和风天气密钥'//替换成开发者申请到的key 12.}, 13.success:function(res){ 14.console.log(res.data); 15.} 16.}) 17.}, 18.}) 将上述函数在生命周期函数onLoad和自定义函数regionChange中分别进行调用,表示当页面加载时和切换城市时均主动获取一次实况天气数据。 JS(pages/index/index.js)代码片段修改如下: 1.Page({ 2./** 3.* 更新省、市、区信息 4.*/ 5.regionChange: function(e) { 6.this.setData({region: e.detail.value}); 7.this.getWeather();//更新天气 8.}, 9./** 10.* 生命周期函数--监听页面加载 11.*/ 12.onLoad: function(options) { 13.this.getWeather();//更新天气 14.}, 15.}) 在联网状态下保存后重新运行会在Console控制台得到第三方服务器发回的JSON数据,如图518所示。 图518Console控制台获取到服务器返回数据 由图可见,实况天气数据包含在HeWeather6[0].now属性中。更新getWeather函数,将该属性存到JS文件的data中,JS(pages/index/index.js)代码片段修改如下: 1.Page({ 图519AppData面板获取到数据 2./** 3.* 获取实况天气数据 4.*/ 5.getWeather: function() { 6.var that = this; 7.wx.request({ 8.url: 'https://free-api.heweather.com/s6/ weather/now', 9.data:{ 10.location:that.data.region[1], 11.key:'f0671b6589ff43019e72970d334ea93e' 12.}, 13.success:function(res){ 14. that.setData({now:res.data.HeWeather6[0].now}); 15.} 16.}) 17.}, 18.}) 此时重新运行将在AppData面板中查到已经被记录的天气数据,如图519所示。 之后只需要将这些数据更新到页面上即可显示出来。 视频讲解 5.5.3更新页面天气信息 将WXML页面上所有的临时数据都替换成{{now.属性}}的形式,例如温度是{{now.tmp}}。 WXML(pages/index/index.wxml)代码片段修改如下: 1. 2. 3.… 4. 5.{{now.tmp}}℃ {{now.cond_txt}} 6. 7. 8. 9. 10. 11.湿度 12.气压 13.能见度 14. 15. 16.{{now.hum}} % 17.{{now.pres}} hPa 18.{{now.vis}} km 19. 20. 21.风向 22.风速 23.风力 24. 25. 26.{{now.wind_dir}} 27.{{now.wind_spd}} km/h 28.{{now.wind_sc}} 级 29. 30. 31. 运行效果如图520所示。 需要注意的是,在网速受限的情况下可能不能立刻获取到数据,因此最好在JS文件的data中为now规定 初始数据,在获取到实际数据前可以临时显示这些数据。 JS(pages/index/index.js)代码片段修改如下: 1.Page({ 2./** 3.* 页面的初始数据 4.*/ 5.data: { 6.region: ['安徽省', '芜湖市', '镜湖区'], 7.now:{ 8.tmp:0, 9.cond_txt:'未知', 10.cond_code:'999', 11.hum:0, 12.pres:0, 13.vis:0, 14.wind_dir:0, 15.wind_spd:0, 16.wind_sc:0 17.} 18.}, 19.}) 在网速受限的状态下,初始数据显示效果如图521所示。 图520实况天气数据显示效果 图521初始数据显示效果 此时项目就全部完成了。 5.6完整代码展示 app.json文件的完整代码如下: 1.{ 2."pages": [ 3."pages/index/index" 4.], 5."window": { 6."navigationBarBackgroundColor": "#3883FA", 7."navigationBarTitleText": "今日天气" 8.} 9.} app.wxss文件的完整代码如下: 1./*背景容器样式*/ 2..container{ 3.height: 100vh; /*高度为100视窗,写成100%无效*/ 4.display: flex; /*flex布局模型*/ 5.flex-direction: column; /*垂直布局*/ 6.align-items: center;/*水平方向居中*/ 7.justify-content: space-around;/*调整内容位置*/ 8.} WXML文件(pages/index/index.wxml)的完整代码如下: 1. 2. 3. 4. 5.{{region}} 6. 7. 8. 9.{{now.tmp}}°C {{now.cond_txt}} 10. 11. 12. 13. 14. 15. 16. 17.湿度 18.气压 19.能见度 20. 21. 22.{{now.hum}} % 23.{{now.pres}} hPa 24.{{now.vis}} km 25. 26. 27.风向 28.风速 29.风力 30. 31. 32.{{now.wind_dir}} 33.{{now.wind_spd}} km/h 34.{{now.wind_sc}} 级 35. 36. 37. WXSS文件(pages/index/index.wxss)的完整代码如下: 1./*文本样式*/ 2.text{ 3.font-size: 80rpx; 4.color:#3C5F81; 5.} 6. 7./*图标样式*/ 8.image{ 9.width: 220rpx; 10.} 11. 12./*区域4整体样式*/ 13..detail{ 14.width: 100%; 15.display: flex; 16.flex-direction: column; 17.} 18./*区域4单元行样式*/ 19..bar{ 20.display: flex; 21.flex-direction: row; 22.margin: 20rpx 0; 23.} 24./*区域4单元格样式*/ 25..box{ 26.width: 33.3%; 27.text-align: center; 28.} JS文件(pages/index/index.js)的完整代码如下: 1.Page({ 2./** 3.* 页面的初始数据 4.*/ 5.data: { 6.region: ['安徽省', '芜湖市', '镜湖区'], 7.now:{ 8.tmp:0, 9.cond_txt:'未知', 10.cond_code:'999', 11.hum:0, 12.pres:0, 13.vis:0, 14.wind_dir:0, 15.wind_spd:0, 16.wind_sc:0 17.} 18.}, 19./** 20.* 更新省、市、区信息 21.*/ 22.regionChange: function(e) { 23.this.setData({region: e.detail.value}); 24.this.getWeather();//更新天气 25.}, 26./** 27.* 获取实况天气数据 28.*/ 29.getWeather: function() { 30.var that = this; 31.wx.request({ 32.url: 'https://free-api.heweather.com/s6/weather/now', 33.data:{ 34.location:that.data.region[1], 35.key:'请填入开发者申请的和风天气密钥'//替换成开发者申请到的key 36.}, 37.success:function(res){ 38.that.setData({now:res.data.HeWeather6[0].now}); 39.} 40.}) 41.}, 42./** 43.* 生命周期函数--监听页面加载 44.*/ 45.onLoad: function(options) { 46.this.getWeather();//更新天气 47.} 48.})