3.2天气查询
3.2.1登录首页
根据上文分析的设计框架,我们现在pages目录下依次创建index、weather、city、virus的文件夹。并在weather文件下创建weather.wxml、weather.wxss、weather.js、weather.json、在calculator目录下创建calculator.wxml、calculator.wxss、calculator.js、calculator.json、新建src文件夹,在src下面创建img文件夹和icon文件夹,分别用来存放背景图片.png和天气图标,ec-canvas文件夹用来存放天气元素的动态画布。要理清楚目录树的结构层次,才能在后面的页面跳转时做好代码的调用。我事先将我的用户头像放在src/img/menu-img.jpg路径下,在index.wxml中通过调用系统函数userinfo-avatar,判断用户是否上传了头像,有就显示没有就显示默认,调用userInfo.name函数,系统自动获取用户名字。 定义一对 标签,为“实用工具”,我们再在这对标签里面分别并列定义“天气&疫情”和“计算器”标签,再去index.wxss定义样式,用户信息显示为宽度100%,高度自动,文字居中显示,用户名宽度100%,高度2像素(用iPhone6作为模拟机,其整个屏幕是750像素),转到index.js页面,我们在Page的data中可以编辑 userInfo的文本文字内容,我们给文字设置下样式,文字大小0.8像素,文字居中左对齐字符间距0.2像素。
/**index.wxss**/ .placeholder{ margin: 5px; padding: 0 10px; text-align: center; background-color: #EBEBEB; height: 2.3em; line-height: 2.3em; color: #333; } .userinfo-show{ width: 100%; height: auto; margin-top: 1em; overflow: hidden; text-align: center; } .userinfo-avatar{ width: 8em; height: 8em; margin: 0 auto; display: block; border-radius: 50%; } .userinfo-nickname{ width: 100%; height: 2em; line-height: 2em; font-size: 1.2em; font-weight: bold; } .userinfo-post{ font-size: .9em; color: #8B8B83; padding:0 2em; } .userinfo-desc{ font-size: .8em; color: #B3B3B3; text-align: left; padding:1em 2em; text-indent: 1.6em; }
3.2.2当天及未来三天天气信息的函数封装
先在weather.json中设置navigationBarTitleText导航栏名字为天气查询,该页面就配置完成,在weather.wxml设置天气界面的显示背景图,我们是外部引用map.png的方式作为该页面的大背景底色,模式为aspectFit,保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。图片版式为cover,重复覆盖,因为考虑到不同的机型,不同的操作系统,有可能使得图片失真,这样做就会在不同的机型上显示效果都是一样的比例。先申明todyWeather.style函数,其中包括了todayWeather.city、todayWeather.realtimeTemperature、todayWeather.temperature、todayWeather.wind、todayWeather.pm25函数。在weather.wxml中申明futureThreeDay函数,给该函数定义关键字key,并用*this指针指向该变量的地址,在该函数下调用weather-item下面的item.date函数,把未来三天的天气信息传给futureThreeDay函数。给未来三天天气添加ui图标元素,调用iconItem.src,将天气图标传入进来。调用item.temperature函数,能显示未来三天的温度。
3.2.3 设置24小时天气和页面动态特效
在weather.wxss中我们可以为刚刚在在wxml页面设置的元素配置样式,显示样式为block块级显示,不隐藏;地图图标设置高度20像素,宽度20像素,水平居中显示;实时温度显示字体大小为5像素,文字水平居中,高度2像素,宽度100%,不溢出;天气信息左对齐,字体大小14像素,行高22像素,高度22像素;天气图标高度5像素,宽度5像素;PM2.5信息高度30像素,行高30像素,右对齐,距离上部15像素,边框1像素,白色实线,圆角边框,宽度自动。这时候我们去weather.js中定义这些函数。在Page中的data里面定义变量todayWeather,在事件处理函数dealTodayData: function(data)中,给函数传一个data传参,定义返回值result来接受天气信息的结果。
3.2.4 天气类相关生活指数
在天气查询的下面有相关生活指数的提醒,定义生活指数,绑定用户点击事件,设置hover样式为none,给定背景图片,在天气类的wxss里设置一周的天气变化,气温,平均气温,风向,温度外部引用第三方百度mapAPI来传参。markLine:data: new Array(nowData.length).keys()].map((ele,index)用来显示表格虚线,通过eventChannel向被打开页面传送数据res.eventChannel.emitaccept DataFromOpenerPage.
3.2.5 设置页面效果
我们知道,一年的天气变化是很多的,我们不可能将这些所有的天气信息都封装在weather.js,这样做起来,很不利于后面的维护和二次开发,所以我们这里将各类天气信息抽离出来单独封装在weather文件夹下的util.js.我将所有的天气信息定义在数组里 let _arr = ["晴", "多云", "阴", "阵雨", "雷阵雨", ……],用变量str来指向这个数组,通过索引数组下标+1的方法来,用for循环来遍历数组,取出对应的天气信息,同样的,这种方式也可以取出天气对应的图标。用系统的外部引入函数module.exports来引入温度的事件处理函数dealTemperature: (t),将传参指向刚刚定义的数组,能得到此天气下对应的温度。这一步其实就要给图表加上数据,采用 wx.request传入url地址,这里我们调用函数usingComponents": { "ec-canvas": "../../ec-canvas/ec-canvas"采用canvas画布来实现整个页面的动态效果。 ![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/20200426173235669.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0ODA3NzU2,size_16,color_FFFFFF,t_70)
3.2.6城市天气查询
现在大多数天气查询App都有二级页面来定点查询别的城市天气,这里我预留了天气查询的借接口,位于页面的左上(见图3-2-5),在city.wxml里面设置页面布局,城市管理,热门城市searchCity(e)var newList = app.globalData.cities;
在city.wxss里面给宽高样式,调用函数canvas画布来做整个页面的背景色 显示样式display: flex;文字样式justify-content: space-between;宽width: 90%;页边距padding: 10rpx 0; margin: 0 auto;边框box-sizing: border-box;文字居中align-items: center
在城市查询板块下有热门城市管理 热门城市,还是给定宽高样式.hotCity{width: 84%; margin: 0 auto;} 字体大小font-size: 20rpx;字体颜色color: rgba(255, 255, 255);边距margin-top: 40rpx;margin-bottom: 10rpx;文字居左text-align: left;宽width: 100%
import * as echarts from '../../ec-canvas/echarts'; let chart = null;let chart2 = null; var app = getApp(); var qurl = 'https://www.tianqiapi.com/api?version=v1&appid=23035354&appsecret=PGgTiHl1&city='+ wx.getStorageSync("cityNow") function setOption(chart, xdata, ydata) { var option = { title: { text: ' 未来一周天气变化', textStyle:{ color:"#FFFFFF", fontSize:16, fontWeight:"normal" }, textAlign:'auto' }, onShareAppMessage: function () { return { title: '欢迎转发我的小程序', path: '/pages/bar/index.js' } }, tooltip: { trigger: 'axis', show:true, formatter:'{a0}: {c0}\n{a1}: {c1}\n{a2}: {c2}' }, xAxis: { type: 'category', boundaryGap: false, data: xdata.map((ele,ind)=>{ return ind===0?("今天"):ele.week }), axisLine:{ lineStyle:{ color:"#FFFFFF" } } }, yAxis: [{ min:function(value){ return value.min }, type: 'value', axisLabel: { formatter: '{value}' }, name:"气温(℃)", nameLocation:"end", axisLine:{ lineStyle:{ color:"#FFFFFF" } } },{ name:"", type: 'value', axisLine:{ lineStyle:{ color:"#FFFFFF" } } }], series: [ { name: '平均气温', type: 'line', data: ydata.map((ele,ind)=>{ return { value:ele.tem.replace("℃","") } }), smooth:true, symbol:"none" }, { name:"风向", type:'line', yAxisIndex:1, data: ydata.map((ele,ind)=>{ return { value:ele.win[0]+ele.win_speed.replace("<","小于") } }) }, { name:"天气", type:'line', yAxisIndex:1, data: ydata.map((ele,ind)=>{ return { value:ele.wea } }) } ] }; chart.setOption(option) } function setOption2(chart, xdata, ydata) { var nowData = ydata[0].hours.concat(ydata[1].hours).filter((ele,ind)=>{ if(parseInt(ele.day.match(/[\u4e00-\u9fa5](\d{2})[\u4e00-\u9fa5]/)[1]) >= new Date().getHours() || parseInt(ele.day.match(/\d{2}/)[0]) > new Date().getDate()){ return true } }); function getMarkLine(ind){ return [{ symbol:"none", lineStyle:{ color:"white" }, coord:[ind,0] },{ symbol:"none", lineStyle:{ color:"white" }, coord:[ind,parseInt(nowData[ind].tem.replace("℃",""))] } ] } var option = { title: { text: '' }, grid:{ left:20, top:30, right:20, bottom:40 }, xAxis: { type: 'category', show:true, boundaryGap:false, data: nowData.map((ele,ind)=>{ return ele.day.match(/[\u4e00-\u9fa5](\d{2})[\u4e00-\u9fa5]/)[1]+"时"+"\n"+ele.wea }), axisLine:{ show:false, lineStyle:{ color:"#FFFFFF" } }, "axisTick":{ "show":false }, }, yAxis: [{ type: 'value', show:false }], series: [ { name: '气温', type: 'line', data: nowData.map((ele,ind)=>{ return ele.tem.replace("℃","") }), smooth:false, itemStyle : { normal: { label : {show: true}, lineStyle:{ color:"white" }, color:"white" }}, markLine:{/*显示虚线*/ data: [...new Array(nowData.length).keys()].map((ele,index)=>{ return getMarkLine(index) }) } } ] }; chart.setOption(option) } Page({ data: { weather:[], rain:false, three:[], ec:{ lazyLoad:true }, ec2:{ lazyLoad:true }, weatherInShortTerm:"" }, switch(){ var that = this; wx.navigateTo({ url: '/pages/city/city?style='+this.data.weather[0].wea_img, success: function(res) { // 通过eventChannel向被打开页面传送数据 res.eventChannel.emit('acceptDataFromOpenerPage', {cityData:that.data.weather[0],cityName:that.data.location}) } }) }, configure(){ wx.openSetting({}) }, initChart: function (xdata, ydata) { this.eComponent.init((canvas, width, height) => { const chart = echarts.init(canvas, null, { width: width, height: height }); setOption(chart, xdata, ydata) this.chart = chart; return chart; }); this.eComponent2.init((canvas, width, height) => { const chart2 = echarts.init(canvas, null, { width: width, height: height }); setOption2(chart2, xdata, ydata) this.chart2 = chart2; return chart2; }); },
3.2.8关于第三方API接口调用说明
项目天气接口来源于天气API、疫情接口来源于腾讯新闻。到这里,我们已经天气、新冠疫情等元素、样式、布局、天气信息和各种函数都封装完成,它们都通过API接口发送网络请求返回json的数据格式。这里我们要借助第三方工具来获取位置信息。我们需要调用百度地图的微信小程序API接口才能实时获取位置信息。第一步:先到百度开放平台(http://lbsyun.baidu.com/index.php?
title=wxjsapi/guide/key)申请ak,进入百度开放平台官网,点击右上角API控制台,登录百度账号,根据提示填写正确的邮箱,手机号码完成开发者注册。
第二步:再次点击进入API控制台,创建一个新应用 ,在创建的应用页面,填写应用名称,选择应用类型为“微信小程序”,勾选启用服务,填写AppID,点击提交即可看到申请成功的密钥(ak)。
第三步申请ak成功后在API控制台-我的应用里面就可以看到,复制ak,去微信公众平台的后台配置request合法请求域名。
第四步,下载百度地图的api,将下载好的文件解压拷贝到libs文件夹下,
第五步:在weather.js下引入我们下载的百度地图api的js文件,用绝对路径的方式引用let bmap = require(’…/…/libs/bmap-wx.js’),并且进行配置,通过 onLoad: function(options)初始化页面options跳转所带来的参数,调用百度地图bmap.BMapWX函数,传入我们刚刚申请的密钥ak,得到经纬度,由经纬度来绑定城市,获取到用户的位置。定义query = function()调用BMap.weather函数,发起天气请求,来获取该经纬度下的天气情况。
3.3简易计算器
简易计算器模块相比天气就要简单些,不论是从布局,样式方面,都要单一。能进行+、-、*、/、%运算,这是本项目的副板块,是为了方便用户有时候的计算方便。但是这个板块,需要有很多小细节要考虑到,因此在开发时也要考虑周全。
3.3.1初始化配置页面信息
我们先在calculator.wxml中配置计算器所需的按钮1,2,3,4,5,6,7,8,9,0,+,-,*,/,%,=,.,清屏,删除一共19个按钮,为每一个按钮绑定tapped点击事件,添加id属性。再去calculator.wxss中配置页面每个按钮的位置大小,整个container页面显示横向铺满,背景色#f1f3f3,每一个格子居中对齐,横向铺满,高度100像素;结果显示区域:横向宽度100%;按钮panel-btns:宽度:100%,竖向排列;按钮btns-rows:宽度100%,横向排列,背景色#f7f8f9;,每个按钮:文字水平居中,边框1像素实线,按钮垂直居中。我们在calculator.js中的Page函数下调用tapped点击函数即可,我们定义showAbout: function()函数调用系统wx.showModal函数就可以用来展示该计算器的产品信息说明。
3.3.2计算功能的实现
我将计算功能的部分单独封装在utils文件夹下的calc.js的文件中,先定义了一些静态区常量在内存中,方便后面的直接调用。
INIT: 0,//初始状态;
RESULT: 1,//结果状态;
FIRST_UNDOT: 2, //记录第一个操作数,且该操作数没有小数点;
FIRST_DOT: 3, //记录第一个操作数,且该操作数有小数点;
SECOND_UNDOT: 4, //记录第二个操作数,且该操作数没有小数点;
SECOND_DOT: 5 //记录第二个操作数,且该操作数有小数点;
let curState = STATE.INIT //状态机所在状态;
let curResult = 0 //计算结果
let opNum1 = ‘0’ //操作数1
let opNum2 = ‘’ //操作数2
let op = ‘’ //操作符
let displayNum = opNum1 //界面上应当显示的数值
let displayOp = “” //界面上应当显示的操作符
再重置程序,判断输入的是否为0~9数字,如果是显示区会显示出来,若输入的第一个为0,则就显示0,如果输入是清屏 清除并将数据设置为初始状态;如果是删除 判断被删掉的那个字符是否为“.”不然删掉后就不能打“.”了,当删到最后一个数字时默认为0;判断判断运算符的连接方式,判断最后一个字符是否为数字如果是就可以添加运算符不然就无法输入。如果用户连续输出多个操作符,则最后输入的一个会覆盖前面输入的操作符。最后调用module.exports函数将结果都返回,我们再去calculator.js文件中import { addOp, getVars, reset } from "…/…/utils/calc"调用外部引入即可实现。
'use strict' const STATE = { INIT: 0, //初始状态 RESULT: 1, //结果状态 FIRST_UNDOT: 2, //记录第一个操作数,且该操作数没有小数点 FIRST_DOT: 3, //记录第一个操作数,且该操作数有小数点 SECOND_UNDOT: 4, //记录第二个操作数,且该操作数没有小数点 SECOND_DOT: 5 //记录第二个操作数,且该操作数有小数点 } let curState = STATE.INIT //状态机所在状态 let curResult = 0 //计算结果 let opNum1 = '0' //操作数1 let opNum2 = '' //操作数2 let op = '' //操作符 let displayNum = opNum1 //界面上应当显示的数值 let displayOp = "" //界面上应当显示的操作符 /** * 重置程序状态 */ function reset() { curState = STATE.INIT curResult = 0 opNum1 = '0' opNum2 = '' op = '' } /** * 是否为零 */ function isZero(code) { return code == '0' } /** * 是否数字 */ function isNumber(code) { return code >= '0' && code <= '9' } /** * 是否操作符 */ function isOperator(code) { return code == '+' || code == '-' || code == 'x' || code == '/' || code == '%' } /** * 是否小数点 */ function isDot(code) { return code == '.' } /** * 是否是等号 */ function isEquel(code) { return code == '=' } /** * 是否清屏 */ function isClear(code) { return code == 'c' } /** * 是否删除 */ function isDelete(code) { return code == 'd' } /** * 转换为可现实的操作符 */ function op2Show(code) { return code == '/' ? '÷' : (code == 'x' ? '×' : code) } /** * */ function tryAppend(num, code) { if (num.length < 15) { num += code } return num } function tryTrunc(num) { let str = '' + num if (str.length > 15) { str = str.substr(0, 15) } return str } /** * */ function tryDelete() { if (curState == STATE.SECOND_DOT || curState == STATE.SECOND_UNDOT) { if (opNum2.length > 0) { opNum2 = opNum2.substr(0, opNum2.length - 1) } if (opNum2 == '') { opNum2 = '0' } return } else { if (opNum1.length > 0 && opNum1 != '0') { opNum1 = opNum1.substr(0, opNum1.length - 1) } if (opNum1 == '') { opNum1 = '0' } return } } function tryCalc() { let n1 = parseFloat(opNum1) let n2 = parseFloat(opNum2) switch (op) { case '+': curResult = n1 + n2 break case '-': curResult = n1 - n2 break case 'x': curResult = n1 * n2 break case '/': if (n2 == 0) { reset() curResult = 'NaN' displayOp = '' } else { curResult = n1 / n2 } break case '%': if (n2 == 0) { reset() curResult = 'NaN' displayOp = '' } else { curResult = n1 % n2 } break } curResult = tryTrunc(curResult) } function addOp(code) { switch (curState) { case STATE.RESULT: case STATE.INIT: if (isNumber(code) && !isZero(code)) { curState = STATE.FIRST_UNDOT opNum1 = code } else if (isDot(code)) { curState = STATE.FIRST_DOT opNum1 = '0.' } else if (isOperator(code)) { curState = STATE.SECOND_UNDOT opNum1 = '0' opNum2 = '' op = code } displayNum = opNum1 displayOp = '' break case STATE.FIRST_UNDOT: displayOp = '' if (isNumber(code)) { if (!isZero(opNum1)) { opNum1 = tryAppend(opNum1, code) } else { opNum1 = code } } else if (isDot(code)) { curState = STATE.FIRST_DOT opNum1 = opNum1 == '' ? '0' : tryAppend(opNum1, '.') } else if (isDelete(code)) { tryDelete() } else if (isOperator(code)) { curState = STATE.SECOND_UNDOT op = code opNum2 = '' displayOp = op } displayNum = opNum1 break case STATE.FIRST_DOT: displayOp = '' if (isNumber(code)) { opNum1 = tryAppend(opNum1, code) } else if (isDelete(code)) { tryDelete() if (opNum1.indexOf('.') < 0) curState = STATE.FIRST_UNDOT } else if (isOperator(code)) { curState = STATE.SECOND_UNDOT op = code opNum2 = '' displayOp = op } displayNum = opNum1 break case STATE.SECOND_UNDOT: if (isNumber(code)) { if (!isZero(opNum2)) { opNum2 = tryAppend(opNum2, code) } else { opNum2 = code } displayNum = opNum2 } else if (isDot(code)) { curState = STATE.SECOND_DOT opNum2 = opNum2 == '' ? '0' : tryAppend(opNum2, '.') displayNum = opNum2 } else if (isDelete(code)) { tryDelete() displayNum = opNum2 } else if (isOperator(code)) { if (opNum2 != '') { //直接计算 tryCalc() curState = STATE.SECOND_UNDOT opNum1 = curResult opNum2 = '' displayNum = curResult } op = code displayOp = op } else if (isEquel(code)) { if (opNum2 != '') { tryCalc() curState = STATE.RESULT opNum1 = '0' opNum2 = '' displayNum = curResult } op = code displayOp = op } break case STATE.SECOND_DOT: if (isNumber(code)) { opNum2 = tryAppend(opNum2, code) displayNum = opNum2 } else if (isDelete(code)) { tryDelete() if (opNum2.indexOf('.') < 0) curState = STATE.SECOND_UNDOT displayNum = opNum2 } else if (isOperator(code)) { if (opNum2 != '') { //直接计算 tryCalc() curState = STATE.SECOND_UNDOT opNum1 = curResult opNum2 = '' displayNum = curResult } op = code displayOp = op } else if (isEquel(code)) { if (opNum2 != '') { tryCalc() curState = STATE.RESULT opNum1 = '0' opNum2 = '' displayNum = curResult } op = code displayOp = op } break } if (isClear(code)) { reset() displayNum = opNum1 displayOp = '' } displayOp = op2Show(displayOp) } reset() module.exports = { reset, addOp, getVars(){ return {curState, curResult, opNum1, opNum2, op, displayNum, displayOp} } }
3.4页面跳转与交互
到这里,三大页面的功能都已经完成,现在要做的是将这三个页面能通过封装的函数调用起来,实现页面的跳转功能,因为我们要把这些功能能在同一个小程序里工作起来。我们要回到最开始的程序页面index.wxml,我们分别都给天气查询模块和计算器模块添加按钮,绑定点击事件bindtap="weatherSearch"和bindtap=“calc”,再去index.js调用事件处理函数天气页面weatherSearch: () => { wx.navigateTo({url:’…/weather/weather’});},,计算器页面事件处理函数calc: () => {wx.navigateTo({url: ‘…/calculator/calculator’});},添加需要跳转的地址即可。
3.4本项目的数据来源
获取当前用户地址
采用微信小程序自带的API接口wx.getLocation,获取当前位置的经纬度
调用第三方百度地图API接口
获取到经纬度后,调用百度地图API获取当前城市以及街道
API接口https://api.map.baidu.com/
调用第三方天气API接口
获取天气的API接口
API接口地址:https://www.tianqiapi.com
调用第三方腾讯疫情新闻API接口
API接口地址https://view.inews.qq.com
绘制中国地图,通过canvas画布来传入图表,调用mapData的库函数,
4 项目的代码调试及线上发布
4.1代码编译调试
打开调试器,运行小程序后观察控制台console打印的结果,在Network看的出整个项目的网络请求时长,Audits上面能对本次小程序从页面渲染、网络、JS脚本等方面评估小程序的性能进行综合评估。
代码上传后,开发人员可以提交代码以供审核。在这之前我们需要找到提交审核的页面。转到微信公众平台(http://mp.weixin.qq.com)并使用微信扫码登录。点击管理-版本管理,找到“开发版本”项,可以找到刚上传的代码。单击左侧的“提交审核”,使用管理员的微信扫码来验证并确认即可。接下来只要等待审核结果。(我的微信小程序已上线,直接在微信-小程序-搜本科毕业设计)
4.2 线上审核发布
小程序开发完成后,开发者要把本地代码上传至开发者公众台后台。打开需要提交新版本的项目,单击左侧菜单栏的“上传”按钮,扫码确认身份。填写所提交代码的版本号,项目说明等。确认正确后,代码会压缩上传到后台“开发版”。注意,“开发版本”只允许存放一个,新加载上传的代码会替换原来“开发版本”中的代码。
5 总结
本项目是基于微信开发者工具完成的,采用WXML+WXSS+JavaScript为开发语言,JSON为数据格式来实现的,因为是基于微信小程序的天气预报终端开发,不需要开发者购买域名和搭建服务器,微信提供了很多第三方API接口和云服务器,能节省经费。你在微信开发者工具的编辑器内写代码,编译通过后,模拟器上会显示微信端的效果,这种实时反馈是我特别喜欢的。在整个项目开发过程中,能让我把以前的学过的零零散散的旧知识都整合到一起,提高我的编程能力,更加熟练函数的封装调用,系统函数的调用,在整个项目的开发中,我也遇到许许多多bug,通过查询资料一一解决,我收获的更多,本项目也有不少新知识,比如第三方工具的使用,调用外部的API接口等,这些问题对我今后的编程思维有极大的促进作用。增强了我的动手能力和解决问题的能力,培养了我对编程的兴趣和热爱。
参考文献
[1] 王天泥. 当图书馆遇上微信小程序 图书与情报[J] 2016-12-15(12)23-25
[2] 李雪钊. 基于微信小程序的慢出行共享系统的设计与实现 首都经济贸易大学[D] 2018-05-01(26)55-57
[3] 张雪云,牟艳,张九博 基于微信小程序的电源监测管理系统设计 计算机与现代化[J] 2017-12-15(37)86-88
[4]王松 基于用户需求的高校图书馆微信小程序移动服务设计研究 东北师范大学[D] 2018-05-01(11)54-55
[5] 代洪彬 基于微信小程序的《计算机应用基础》微学习平台的设计与实现
广西师范学院[D] 2018-04-01(21)22-24
[6]韦玉辉; 苏兆伟; 潘梦诗 基于微信小程序的服装个性化定制系统设计与实现 服装学报[J] 2019-10-15(58)14-15
[7]王婷婷;谢晓茹;于佳微信小程序对移动互联网生态圈的影响[J].电脑知识与技术2018-11-15(74)34-36
[8]苏煜辉; 杨明戊; 陈正铭; 戴经国.浅析快应用与微信小程序技术的异同[J].电脑知识与技术,2018-11-05(75)19-21.
[9]荣蓉;穆心驰;实战微信小程序JavaScript、WXML与Flexbox综合开发[M]北京:电子工业出版社 , 2017.07:132-136
[10]刘明洋;微信小程序实战入门内含完整实例解析[M] 北京:人民邮电出版社 , 2017.10:56-78
[11] 闫小坤;微信小程序开发详解[M] 北京:清华大学出版社 , 2017.07:89-92
[12]厉业崧;王向辉;微信小程序入门[M] 北京:清华大学出版社 , 2017.11:23-26
[13]微信小程序百度百科https://baike.baidu.com/item/微信小程序/20171697?fr=aladdin
[14]微信小程序开发官方文档https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/#小程序简介
[15]百度地图开发平台JavaScript API https://lbsyun.baidu.com/index.php?title=jspopular3.0
[16]刘刚.微信小程序开发必备100Tip[M] 北京:电子工业出版社 , 2017.10
[17]朱继宏.微信小程序开发与运营[M] 北京:电子工业出版社 , 2018.11:12-25
[18]周文洁.微信小程序开发零基础入门[M] 北京:清华大学出版社 , 2019.01:36-39
[19]雷磊.微信小程序开发入门与实践[M] 北京:清华大学出版社 , 2017.04:22-31
[20]刘刚.微信小程序开发图解案例教程[M] 北京:人民邮电出版社 , 2019.01:89-93