O_微信小程序之课程设计


MZTools小程序


  MZTools

参考

  微信小程序开发文档(官方)
  微信小程序开发文档(W3Cschool)

引言

概述

  微信之父张小龙是这样描述小程序的: 小程序是一个不需要下载安装就可使 用的应用,它实现了应用触手可及的梦想, 用户扫一扫或者搜一下即可打开应用。 也体现了用完即走的理念, 用户不用关心是否安装太多应用的问题。 应用将无处 不在,随时可用,但又无需安装卸载。非常便捷。

  微信小程序优势 1. 小——安装包小于 2M。 2. 快——用户体验更快,无需开启、登录、注册、认证等。 3. 成本低——研发维护成本更低 单一平台。 4. 微信用户体系大——日活跃用户达 8.99 亿。 5. 场景化快速应用。 6. 与公众号强强关联互动,形成内部自我闭环的小生态圈。 7. 支付方便—无需外接支付接口。

  a. 小程序覆盖范围广,可以跨平台访问;同时能够快速的访问以便带来更 好的体验;亲场景亲服务,为线下服务提供了支持。 b. 灵活性强。由于微信客户可以在微信聊天中进入小程序,也可以在小程 序里随时切换回聊天,灵活快捷。当服务融入生活,场景被切换的足够 小足够轻的时候,小程序绝对是你触达最深,服务用户最好的工具。 c. 推广速度快。小程序通过聊天界面可以直接分享,也可以在线下投放二 维码进行推广,十分便捷有效。 d. 小程序与公众号等的结合。小程序与公众号之间存在着多重跳转关系, 可以形成一个紧密的联系,有利于扩大企业品牌影响力。 e. 轻应用。一般我们手机上都有很多高频使用的各种 APP,小程序的出现 大大的缓解了这一压力,很多高频使用的 APP都不在需要,无论对商家 或是用户都很方便。

本设计的任务和主要功能

  使生活更便捷,提高生活办公的效率。主要有时间打卡天气预报、地图、进制转换、手电筒、扫码等功能。

开发环境的安装和配置

开发包及其工具介绍

微信小程序开发工具v1.0.0
  为了帮助开发者简单和高效地开发和调试微信小程序,在原有的公众号网页调试工具的基础上,推出了全新的 微信开发者工具,集成了公众号网页调试和小程序调试两种开发模式。

  使用公众号网页调试,开发者可以调试微信网页授权和微信JS-SDK 详情。

  使用小程序调试,开发者可以完成小程序的 API 和页面的开发调试、代码查看和编辑、小程序预览和发布等功能。

  为了更好的开发体验,从视觉、交互、性能等方面对开发者工具进行升级,推出了 1.0.0 版本。

微信小程序开发助手
  “小程序开发助手” 是微信公众平台发布的官方小程序,帮助开发和运营人员在手机端更方便快捷地查看和预览小程序,扫描下面小程序码可立即体验。

  使用者可以在小程序开发助手查看和预览与自己关联的所有小程序。小程序将会按照其更新时间自动排序,显示在最上面的小程序是最近有提交的小程序,例如开发者预览了新的代码,或者体验版有更新。

  通过点击并展开小程序列表,使用者可以根据自己的身份,浏览到小程序的线上版本、体验版本或开发版本。如果使用者是小程序的管理者,可以浏览到全部三种版本;如果使用者身份是 “体验者”,则可以浏览到线上版本、体验版本,而不会浏览到任何开发版本。

  如果一个小程序有多个开发者,则开发版本的列表将会显示每一个开发者提交预览的最新版本。

开发平台搭建步骤

  https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html下载小程序开发工具最新版本,安装使用。

程序逻辑架构

程序结构图

  程序结构图如图3-1。




图3-1 程序工程结构图

工程文件介绍

JSON 配置

  项目的根目录有一个 app.json 和 project.config.json,此外在 pages/logs 目录下还有一个 logs.json。

小程序配置 app.json
  app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。QuickStart 项目里边的 app.json 配置内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
{
"pages":[
"pages/index/index",
"pages/logs/logs"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle":"black"
}
}

配置各个项的含义:

  • pages字段 —— 用于描述当前小程序所有页面路径,这是为了让微信客户端知道当前你的小程序页面定义在哪个目录。
  • window字段 —— 定义小程序所有页面的顶部背景颜色,文字颜色定义等。

工具配置 project.config.json
  通常大家在使用一个工具的时候,都会针对各自喜好做一些个性化配置,例如界面颜色、编译配置等等,当你换了另外一台电脑重新安装工具的时候,你还要重新配置。

  考虑到这点,小程序开发者工具在每个项目的根目录都会生成一个 project.config.json,你在工具上做的任何配置都会写入到这个文件,当你重新安装工具或者换电脑工作时,你只要载入同一个项目的代码包,开发者工具就自动会帮你恢复到当时你开发项目时的个性化配置,其中会包括编辑器的颜色、代码上传时自动压缩等等一系列选项。

页面配置 page.json
  这里的 page.json 其实用来表示 pages/logs 目录下的 logs.json 这类和小程序页面相关的配置。

  如果整个小程序的风格是蓝色调,那么你可以在 app.json 里边声明顶部颜色是蓝色即可。实际情况可能不是这样,可能你小程序里边的每个页面都有不一样的色调来区分不同功能模块,因此我们提供了 page.json,让开发者可以独立定义每个页面的一些属性,例如刚刚说的顶部颜色、是否允许下拉刷新等等。

WXML 模板

  从事过网页编程的人知道,网页编程采用的是 HTML+CSS+JS 这样的组合,其中 HTML 是用来描述当前这个页面的结构,CSS 用来描述页面的样子,JS 通常是用来处理这个页面和用户的交互。

  同样道理,在小程序中也有同样的角色,其中 WXML 充当的就是类似 HTML 的角色。打开 pages/index/index.wxml,你会看到以下的内容:

1
2
3
4
5
6
7
8
9
10
11
12
<view class="container">
<view class="userinfo">
<button wx:if="{{!hasUserInfo && canIUse}}"> 获取头像昵称 </button>
<block wx:else>
<image src="{{userInfo.avatarUrl}}" background-size="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>

  和 HTML 非常相似,WXML 由标签、属性等等构成。但是也有很多不一样的地方,我们来一一阐述一下:

  • 1、标签名字有点不一样

  往往写 HTML 的时候,经常会用到的标签是 div, p, span,开发者在写一个页面的时候可以根据这些基础的标签组合出不一样的组件,例如日历、弹窗等等。换个思路,既然大家都需要这些组件,为什么我们不能把这些常用的组件包装起来,大大提高我们的开发效率。

  从上边的例子可以看到,小程序的 WXML 用的标签是 view, button, text 等等,这些标签就是小程序给开发者包装好的基本能力,我们还提供了地图、视频、音频等等组件能力。

  • 2、多了一些wx:if这样的属性以及{\{ }}这样的表达式

  在网页的一般开发流程中,我们通常会通过 JS 操作 DOM (对应 HTML 的描述产生的树),以引起界面的一些变化响应用户的行为。例如,用户点击某个按钮的时候,JS 会记录一些状态到 JS 变量里边,同时通过 DOM API 操控 DOM 的属性或者行为,进而引起界面一些变化。当项目越来越大的时候,你的代码会充斥着非常多的界面交互逻辑和程序的各种状态变量,显然这不是一个很好的开发模式,因此就有了 MVVM 的开发模式(例如 React, Vue),提倡把渲染和逻辑分离。简单来说就是不要再让 JS 直接操控 DOM,JS 只需要管理状态即可,然后再通过一种模板语法来描述状态和界面结构的关系即可。

  小程序的框架也是用到了这个思路,如果你需要把一个 Hello World 的字符串显示在界面上。

  WXML 是这么写 :<text>{\{msg}}</text>

  JS 只需要管理状态即可:this.setData({ msg: "Hello World" })

  通过{\{ }}的语法把一个变量绑定到界面上,我们称为数据绑定。仅仅通过数据绑定还不够完整的描述状态和界面的关系,还需要 if/else, for等控制能力,在小程序里边,这些控制能力都用 wx: 开头的属性来表达。

WXSS 样式

  WXSS 具有 CSS 大部分的特性,小程序在 WXSS 也做了一些扩充和修改。

  • 1、新增了尺寸单位。在写 CSS 样式时,开发者需要考虑到手机设备的屏幕会有不同的宽度和设备像素比,采用一些技巧来换算一些像素单位。WXSS 在底层支持新的尺寸单位 rpx ,开发者可以免去换算的烦恼,只要交给小程序底层来换算即可,由于换算采用的浮点数运算,所以运算结果会和预期结果有一点点偏差。

  • 2、提供了全局的样式和局部样式。和前边 app.json, page.json 的概念相同,你可以写一个 app.wxss 作为全局样式,会作用于当前小程序的所有页面,局部页面样式 page.wxss 仅对当前页面生效。

  • 3、此外 WXSS 仅支持部分 CSS 选择器。

JS 交互逻辑

  一个服务仅仅只有界面展示是不够的,还需要和用户做交互:响应用户的点击、获取用户的位置等等。在小程序里边,我们就通过编写 JS 脚本文件来处理用户的操作。

1
2
<view>{{ msg }}</view>
<button bindtap="clickMe">点击我</button>

  点击 button 按钮的时候,我们希望把界面上 msg 显示成 “Hello World”,于是我们在 button 上声明一个属性: bindtap ,在 JS 文件里边声明了 clickMe 方法来响应这次点击操作:

1
2
3
4
5
Page({
clickMe: function() {
this.setData({ msg: "Hello World" })
}
})

  此外你还可以在 JS 中调用小程序提供的丰富的 API,利用这些 API 可以很方便的调起微信提供的能力,例如获取用户信息、本地存储、微信支付等。在前边的 QuickStart 例子中,在 pages/index/index.js 就调用了 wx.getUserInfo 获取微信用户的头像和昵称,最后通过 setData 把获取到的信息显示到界面上。

程序设计

主界面的设计

应用界面



图4-1 应用界面

信息界面



图4-2 登陆及信息界面

关键代码讲解

小程序构架配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
{
"pages":[
"pages/index/index",
"pages/TimeTask/TimeTask",
"pages/Calculator/Calculator",
"pages/PhoneInfo/PhoneInfo",
"pages/Weather/Weather",
"pages/Map/Map",
"pages/HexadecimalC/HexadecimalC",
"pages/Flashlight/Flashlight",
"pages/Clipboard/Clipboard",
"pages/Scan/Scan",
"pages/Setting/Setting",
"pages/sign/sign",
"pages/logs/logs"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "MZTools",
"navigationBarTextStyle":"black"
},
"tabBar": {
"color": "#b2b2b2",
"selectedColor": "#2fcc85",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index",
"text": "应用"
},
{
"pagePath": "pages/sign/sign",
"text": "个人信息"
}
]
}
}

  pages声明页面信息,windows声明小程序整体UI风格,tabBar声明底部切换标签。

时间打卡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
//获取应用实例
var app = getApp()
var util = require('../../utils/util.js');

var tabIndex = 1;
var time_begin = '';
var time_end = '';
var time_show = [0,0,0];
var time_flag = 's0';
var timer;
var inputValue = '';
var modalInputValue = '';
var taskTitle = [];
var taskBeginTime = [];
var taskEndTime = [];
var taskContTime = [];
var taskAddText = [];
var taskJ = [];
var taskI = -1;
var taskTapI = 0;

Page({
data: {
tabIndex: 1,
time_show: [0,0,0],
disabledStart: false,
disabledStop: true,
disabledSett: false,
holdText: '暂停',
inputValue: '',
modalInputValue: '',
modalHiddenAB: true, //是否隐藏
modalHiddenST: true,
modalHiddenTask: true
},


// tab menu 切换
changeTab: function (e) {
var id = e.currentTarget.id;
var that = this;

if (id == 'indexA') {
tabIndex = 1;
this.setData({
tabIndex: 1
});
if (time_flag == 's1'||time_flag == 'h1') {
this.setData({
disabledStart: true
});
}
else {
this.setData({
disabledStart: false
});
}
}
if (id == 'indexB') {
tabIndex = 2;
this.setData({
tabIndex: 2,
disabledStart: true
});
}
if (id == 'indexC') {
tabIndex = 3;
this.setData({
tabIndex: 3,
});
this.onShow();
this.clear();
}
},

//输入框文字同步
inputAB: function(e){
inputValue = e.detail.value;
this.setData({
inputValue: e.detail.value
});
},
modalInputAB: function(e){
modalInputValue = e.detail.value;
this.setData({
modalInputValue: e.detail.value
});
},
settInputH: function (e) {
time_show[2] = e.detail.value;
this.setData({
'time_show[2]': e.detail.value
});
},
settInputM: function (e) {
time_show[1] = e.detail.value;
this.setData({
'time_show[1]': e.detail.value
});
},
settInputS: function (e) {
time_show[0] = e.detail.value;
this.setData({
'time_show[0]': e.detail.value
});
},
settConfirm: function(){ //倒计时开始按钮
this.setData({
modalHiddenST: true,
disabledStart: false,
});
this.showTime();
},
settCancel: function(){
this.setData({
'time_show[2]': 0,
'time_show[1]': 0,
'time_show[0]': 0,
modalHiddenST: true,
});
},

//时间控制
beginTime: function (){
time_begin = util.formatTime(new Date());
this.setData({
time_begin: util.formatTime(new Date())
});
},
endTime: function (){
time_end = util.formatTime(new Date());
this.setData({
time_end: util.formatTime(new Date())
});
},
runTime: function(){
var that = this;
if (time_flag == 's1' || time_flag == 'h1') {
if(tabIndex == 1){
timer = setTimeout(function () {
time_show[0]++;
that.showTime();
that.runTime();
}, 1000);
}
if(tabIndex == 2){
timer = setTimeout(function(){
time_show[0]--;
that.showTime();
that.runTime();
},1000);
}
}
else if (time_flag == 's0' || time_flag == 'h0') {
clearTimeout(timer);
}
},
showTime: function(){
if(time_show[0] >= 60){
time_show[1]++;
time_show[0] = 0;
if(time_show[1] >= 60){
time_show[2]++;
time_show[1] = 0;
}
}
if(time_show[0] < 0){
time_show[1]--;
time_show[0] = 59;
if(time_show[1] < 0){
time_show[2]--;
time_show[1] = 59;
}
}
this.setData({
time_show: time_show
});
},

//按钮控制
start: function(){
time_flag = 's1';
this.setData({
disabledStart: true,
disabledStop: false,
disabledSett: true
});
this.beginTime();
this.runTime();
},
stop: function(){
time_flag = 's0';
this.endTime();
this.setData({
disabledStop: true,
disabledSett: false,
modalHiddenAB: false,
});
if (tabIndex == 0) {
this.setData({
disabledStart: false
});
}
if(tabIndex == 2){
this.setData({
disablesStart: true
});
}
},
hold: function(){
if(time_flag == 's1' || time_flag == 'h1'){
time_flag = 'h0';
this.setData({
holdText: '继续'
});
}
else if(time_flag == 'h0'){
time_flag = 'h1';
this.setData({
holdText: '暂停'
});
this.runTime();
}
},
sett: function(){
this.setData({
modalHiddenST: false,
});
},
clear: function(){
time_begin = '';
time_end = '';
time_show = [0, 0, 0];
time_flag = 's0';
inputValue = '';
modalInputValue = '';
clearTimeout(timer);
this.setData({
time_begin: time_begin,
time_end: time_end,
time_show: time_show,
time_flag: time_flag,
inputValue: inputValue,
modalInputValue: modalInputValue,
disabledStop: true,
disabledSett: false
});
if (tabIndex == 1) {
this.setData({
disabledStart: false
});
}
if (tabIndex == 2) {
this.setData({
disabledStart: true,
});
}
},

//弹窗
modalAB: function(){
if(inputValue == ''){
inputValue = '无标题';
}

taskI++;

taskJ[taskI] = taskI;
taskTitle[taskI] = inputValue;
taskBeginTime[taskI] = time_begin;
taskContTime[taskI] = time_show;
taskEndTime[taskI] = time_end;
taskAddText[taskI] = modalInputValue;
tabIndex = 3;
this.setData({
modalHiddenAB: true,
taskJ: taskJ,
taskTitle: taskTitle,
taskBeginTime: taskBeginTime,
taskContTime: taskContTime,
taskEndTime: taskEndTime,
taskAddText: taskAddText,
tabIndex: tabIndex
});
this.onShow();
this.clear();
},

//任务列表
onLoad: function () {
//数据读取
taskTitle = wx.getStorageSync('title') || [];
taskBeginTime = wx.getStorageSync('begintime') || [];
taskEndTime = wx.getStorageSync('endtime') || [];
taskContTime = wx.getStorageSync('conttime') || [];
taskAddText = wx.getStorageSync('addtext') || [];
taskJ = wx.getStorageSync('j') || [];
taskI = wx.getStorageSync('i') || -1;
this.onShow();
},

onShow: function () {
taskTitle = taskTitle;
taskBeginTime = taskBeginTime;
taskContTime = taskContTime;
taskEndTime = taskEndTime;
taskAddText = taskAddText;
taskJ = taskJ;
taskI = taskI;
this.setData({
taskTitle: taskTitle,
taskBeginTime: taskBeginTime,
taskEndTime: taskEndTime,
taskContTime: taskContTime,
taskAddText: taskAddText,
taskJ: taskJ,
taskI: taskI
});
},
onHide: function () {
//数据存储
wx.setStorageSync('title', taskTitle);
wx.setStorageSync('begintime', taskBeginTime);
wx.setStorageSync('endtime', taskEndTime);
wx.setStorageSync('conttime', taskContTime);
wx.setStorageSync('addtext', taskAddText);
wx.setStorageSync('j', taskJ);
wx.setStorageSync('i', taskI);
},
onUnload: function () {
wx.setStorageSync('title', taskTitle);
wx.setStorageSync('begintime', taskBeginTime);
wx.setStorageSync('endtime', taskEndTime);
wx.setStorageSync('conttime', taskContTime);
wx.setStorageSync('addtext', taskAddText);
wx.setStorageSync('j', taskJ);
wx.setStorageSync('i', taskI);
},

tapi: function (e) {
taskTapI = parseInt(e.currentTarget.id);
this.setData({
modalHiddenTask: false
});
},
taskConfirm: function () {
var s = 0;
console.log(taskTapI);
console.log(taskI);
if (taskTapI == taskI) {}
else {
for (s = taskTapI; s <= taskI; s++) {
console.log(s);
taskTitle[s] = taskTitle[s + 1];
taskBeginTime[s] = taskBeginTime[s + 1];
taskEndTime[s] = taskEndTime[s + 1];
taskContTime[s] = taskContTime[s + 1];
taskAddText[s] = taskAddText[s + 1];
}
}
taskTitle.splice(taskI, 1);
taskBeginTime.splice(taskI, 1);
taskEndTime.splice(taskI, 1);
taskContTime.splice(taskI, 1);
taskAddText.splice(taskI, 1);
taskJ.splice(taskI,1);
taskI--;

this.setData({
taskTitle: taskTitle,
taskBeginTime: taskBeginTime,
taskEndTime: taskEndTime,
taskContTime: taskContTime,
taskAddText: taskAddText,
taskI: taskI,
taskJ: taskJ,
modalHiddenTask: true
});
this.onShow();
},
taskCancel: function () {
this.setData({
modalHiddenTask: true
});
},

onShareAppMessage: function () {

}
})

天气预报

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
var bmap = require('../../utils/bmap-wx.min.js');

Page({
data:{
ak:'rjs4KwwqzmgwstP0cOPRSlraLKSneVWY',
weatherData:'',
futureWeather:[]
},

onLoad: function (options){
var that = this;
var BMap = new bmap.BMapWX({
ak: that.data.ak
});
var fail = function(data){
console.log(data);
};
var success = function (data){
console.log(data);
var weatherData = data.currentWeather[0];
var futureWeather = data.originalData.results[0].weather_data;
console.log(futureWeather);
that.setData({
weatherData: weatherData,
futureWeather: futureWeather,
});
}
BMap.weather({
fail: fail,
success: success
});
},

onShareAppMessage: function () {

}
})

  调用百度地图API的天气接口获取天气数据存入数组,在WXML中绑定数据显示。

地图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
var QQMapWX = require('../../utils/qqmap-wx-jssdk.min.js');
var tabIndex = 1;
Page({
data: {
tabIndex: 1,
currentLon: '',
currentLat: '',
markers: [],
},

changeTab: function (e) {
var id = e.currentTarget.id;
var that = this;
if (id == 'indexA') {
tabIndex = 1;
this.setData({
tabIndex: 1
});
}
if (id == 'indexB') {
tabIndex = 2;
this.setData({
tabIndex: 2,
});
}
if (id == 'indexC') {
tabIndex = 3;
this.setData({
tabIndex: 3,
});
}
},

onLoad: function (res) {
var that = this;
this.getCurrentLocation();
},

getCurrentLocation: function () {
var that = this;
wx.getLocation({
type: 'gcj02', //用wgs84方式会有一定的偏差
success: function (res) {
var latitude = res.latitude; //经度
var longitude = res.longitude; //维度
console.log('location', res);
that.setData({
currentLat: latitude,
currentLon: longitude,
//markers: [{ latitude: latitude, longitude: longitude, icoPath: '' }]
});
that.configMap();
},
})
},
configMap: function () {
var that = this;
var qqmapsdk = new QQMapWX({
key: 'OLIBZ-TG2W3-I7Q3I-3FGKQ-I5NJK-RJFKB'
});
console.log('经纬度', that.data.currentLat ,that.data.currentLon);
qqmapsdk.search({
keyword: '超市',
location: {
latitude: that.data.currentLat,
longitude: that.data.currentLon
},
success: function (res) {
console.log('qqmap_success', res);
},
fail: function (res) {
console.log('qqmap_fail', res);
}
});
},
// 点击搜索框
bindSearchTap: function () {
var that = this
wx.chooseLocation({
success(res) {
var latitude = res.latitude;
var longitude = res.longitude;
console.log(res)
that.setData({
currentLat: latitude,
currentLon: longitude,
markers: [{ latitude: latitude, longitude: longitude, icoPath: '' }]
});
}
});
},

onShareAppMessage: function () {

}
})

  调用腾讯地图API获取当前位置经纬度信息及周边信息,在WXML页绑定数据进行动态更新。搜索框调用小程序自带地图进行搜索定位。

进制转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
var vB = '';
var vO = '';
var vD = '';
var vH = '';
var iId = '0';
var iValue = '';

Page({
data: {
vB: '',
vO: '',
vD: '',
vH: ''
},

hId: function (e){
iId = e.target.id;
},
hValue: function (e){
iValue = e.detail.value;
},

hChange: function (e){
if (iId == 'iB'){
iValue = parseInt(iValue, 2);
}
else if (iId == 'iO') {
iValue = parseInt(iValue, 8);
}
else if (iId == 'iD') {
iValue = parseInt(iValue, 10);
}
else if (iId == 'iH') {
iValue = parseInt(iValue, 16);
}
vB = iValue.toString(2);
vO = iValue.toString(8);
vD = iValue.toString(10);
vH = iValue.toString(16);

this.setData({
vB: vB,
vO: vO,
vD: vD,
vH: vH
});
},

hClear:function (){
vB = '';
vO = '';
vD = '';
vH = '';
iId = '0';
iValue = '';
this.setData({
vB: vB,
vO: vO,
vD: vD,
vH: vH,
iId: iId,
iValue: iValue,
});
},

onShareAppMessage: function () {

}
})

  用parseInt()函数将输入的各数据转换为10进制,再用toString()函数转换为其它各进制显示,理论支持2-32进制所有的进制转换。

手电筒

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
var bgColor = 'black';
var switchFlag = 0;
var currentLight = 0;

Page({
data: {
bgColor: 'black',
switchFlag: 0,
currentLight: 0
},

btnSwitch: function (){
if(bgColor=='black'){
bgColor = 'white';
switchFlag = 1;
currentLight = 0.5;
}
else if(bgColor=='white'){
bgColor = 'black';
switchFlag = 0;
currentLight = 0;
}
wx.setScreenBrightness({
value: currentLight
});
this.setData({
bgColor: bgColor,
switchFlag: switchFlag,
currentLight: currentLight*100
});
},

lightChanging: function (e){
var ligthTmp = e.detail.value;
currentLight = ligthTmp/100;
wx.setScreenBrightness({
value: currentLight
});
},

onShareAppMessage: function () {

}
})

  调用wx.setScreenBrightness()接口设置屏幕亮度及动态变换屏幕背景色实现手电筒功能,由于小程序官方不支持直接打开后置闪光灯,暂时只提供屏幕手电筒功能。

扫码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Page({
data: {
result: ''
},

scanCode() {
var that = this
wx.scanCode({
success(res) {
that.setData({
result: res.result
})
},
});
},

onShareAppMessage: function () {

}
})

  调用wx.scanCode()接口实现扫码功能。

程序测试

  真机体验可在微信搜索“MZTools”或关注公众号“MengZeATY”进入小程序菜单或微信扫描下方二维码。



图5-1 MZTools小程序码

时间打卡


      

天气预报



图5-2 天气预报测试

图5-3 天气预报接口返回数据包

地图





图5-4 地图测试
     


图5-5 地图搜索界面


图5-6 地图接口返回数据包




图5-7 地图搜索测试
     


图5-8 地图周边界面


进制转换



图5-9 进制转换测试

手电筒





图5-10 手电筒关闭状态
     


图5-11 手电筒开启状态


扫码





图5-12 扫码返回结果
     


图5-13 扫码测试用二维码



小结

  MZTools工具集v2.20版本计划功能已全部实现,除地图周边显示外,其他功能均已达到预期要求,更加熟悉了小程序的一些常用组件及小程序官方API的使用技巧,同时加深了对WEB前端的理解和应用。

  更多更完善的功能将在MZTools的v3.0版本推出,计划新增微信运动、罗盘指南针、单位转换、科学计算器、图音视媒体文件的支持开发等功能。

参考文献

[1] Tencent,小程序开发者社区[DB/OL],https://developers.weixin.qq.com,2018.10.15
[2] Tencent,小程序开发者文档[EB/OL] ,https://developers.weixin.qq.com/miniprogram/dev/index.html?t=18101612,2018.10.15