小程序设计
1.小程序总体设计
1.1 小程序总体设计思路
首先根据小程序的功能需求大致确定有哪些界面及具体到界面元素,然后根据每个界面需要的数据,及界面之间的数据流来设计数据库。具体执行流程为:将用户输入的数据存入到云数据库,然后用户可以点击界面元素调用云函数对云数据库进行增删改查,最后从云数据库中获取数据并展示给用户。
1.2.小程序总体结构设计
通过微信搜索待办清单访问该小程序,首先会进入【查看所有任务】页面,在该页面可查看数据库中已添加的所有任务,在这个页面可点击右下方的加号按钮跳转到【待办任务添加】页面。点击提交后会把填入表单的数据存放在todos云数据库中,并自动刷新页面以添加下一个任务,点击左上方箭头回到【查看所有任务】页面。点击任务单元格可跳转到【任务详情】页面,在这个页面可看到任务的具体内容和实现导航功能。
2.数据库设计
结合小程序的功能可知其所需的主要数据有:任务名称、任务状态、任务地点、任务时间、任务图片等。由于本小程序是基于小程序云开发实现的,所以无需自建数据库。
2.1 数据库逻辑结构设计
| 字段名称 | 字段类型 | 允许空值 | 备注 |
|---|---|---|---|
| -Id | string | 否 | 任务ID |
| _openid | string | 否 | 用户身份ID |
| formId | string | 否 | 表单ID |
| image | string | 是 | 任务图片 |
| location | object | 是 | 任务地址 |
| state | string | 否 | 任务状态 |
| time | string | 否 | 任务时间 |
| title | string | 否 | 任务名称 |
小程序实现
1.待办任务添加模块
这个页面是有一个能够获取输入的数据并上传至云数据库todos,当点击选择时间单元格能从底部弹起的滚动选择器来选择定时提醒的时间、点击选择图片单元格能从获取手机相册中的图片并在页面上展示选择的图片、点击选择地点单元格能。。。点击重置按钮能当你选择错误的时间、图片、或地点能够重新选择;点击提交按钮能将表单数据上传至云数据库。
1.1实现创建云数据库并添加数据
-
在app.json文件中声明全局组件并新建addTodo页面,该页面只有一个form表单,该表单设定属性bindsubmit="onSubmit" bindsubmit="onReset"用于携带 form 中的数据触发 submit 事件——将数据上传至云数据库
-
在云开发控制台中创建todos数据集并在addTodo.js中初始化引入todos云数据库
// pages/addTodo/addTodo.js
const db = wx.cloud.database();
const todos = db.collection("todos")
- 点击提交按钮(设定属性form-type="submit")触发onSubmit事件,实现把表单获取到的数据上传至云数据库todos
onSubmit:function(e){
todos.add({
data: {
title: e.detail.value.title,
state: e.detail.value.state,
image: this.data.image,
location:this.pageData.locationObj,
time:time,
formId: e.detail.formId
}
}).then(res => {//打印console信息确保数据添加成功
wx.showToast({
title: '数据添加成功!',
//数据添加成功后跳转到对应的条目详情页面
success:res2=>{
wx.redirectTo({
url:
`../todoInfo/todoInfo?id=${res._id}`,
// url: "../addTodo/addTodo",
})
}
})
})
}
1.2实现为任务选择定时提醒的时间
①使用小程序的模板消息和wx-js-utils发送模板消息的功能包来完成发送模板消息的功能。为form表单增加新的属性report-submit来获取formId ②创建云函数sendMsg并为其安装wx-js-utils,参照官方发表的发送模板消息并填写已知参数 ③创建云函数runner,创建定时触发器,使其每分钟触发一次,如若符合筛选条件,则使用wx.cloud.callFunction来调用云函数sendMsg并向其传入formId(提交的表单的id)和taskId(数据库中的任务id)
// runner.js
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
//引入数据库todos
const db = cloud.database();
const todos = db.collection("todos");
// 云函数入口函数
exports.main = async (event, context) => {
let myDate = new Date;
let month = myDate.getMonth() + 1;
let day = myDate.getDate();
let year = myDate.getFullYear();
// let hour = myDate.getHours();
let minute = myDate.getMinutes();
let time = `${year}-${month}-${day} ${minute}:00`;
// let time = "2019-11-2 18:38";
//1.筛选所有未完成的数据数据{当前时间来筛选}
let tasks =await todos.where({
state:'进行中',
time:time
}).get().then(console.log);
//2.执行数据的提醒
//task是包含在data中的,所以要先对data进行for循环
for(i=0; i<tasks.data.length; i++){
//在runner云函数调用sendMsg云函数
await cloud.callFunction({
name: 'sendMsg',
//传数据
data: {
formId: tasks.data[i].formId,
taskId: tasks.data[i]._id
}
}).then(console.log)
}
const wxContext = cloud.getWXContext()
return {
event,
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
}
//runner/config.json
{
"triggers": [
{
"name": "myTrigger",
"type": "timer",
"config": "0 * * * * * *"//每分钟触发一次
}
]
}
1.3 实现为任务添加图片附件并展示(有则显示)
①使用云开发提供的wx.cloud.uploadFile来实现将本地资源上传至云存储空间。如若上传成功会得到fileID,并将其作为image的来源 ②将这个fileID作为image的值加入到onSubmit方法的数据集里,为云数据库todos增加一个image属性
//展示图片
bindTimeChange:function(e){
this.setData({time:e.detail.value})
},
//选择图片
selectImage: function (e) {
wx.chooseImage({
success: res => {
// tempFilePath可以作为img标签的src属性显示图片
console.log(res.tempFilePaths[0])
//把图片上传到数据库
wx.cloud.uploadFile({
//云存储路径,每次上传不一样的名字
cloudPath: `${Math.floor(Math.random()*1000)}.jpg`,
// 要上传文件资源的路径
filePath: res.tempFilePaths[0]
}).then(res => {
//预览图片
this.setData({ image:res.fileID})
}).catch(err => {
console.error(err)
})
}
})
},
1.4 实现选择任务地点(有则显示)
①使用云开发提供的wx.getLocation(Object object)来实现获取当前的地理位置,使用wx.chooseLocation(Object object)打开地图选择位置。在获取位置信息前要完成用户授权,即在app.json中配置scope.userLocation
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于任务的设定"
}
}
②为选择位置单元格绑定selectLocation事件,在其中添加wx.chooseLocation()来选择位置。构建地址对象locationObj结构体 ③将这个locationObj作为location的值加入到onSubmit方法的数据集里,为云数据库todos增加一个location属性
selectLocation: function () {
wx.chooseLocation({
success: res => {
//构建一个地址对象
let locationObj = {
latitude: res.latitude,
longitude: res.longitude,
address: res.address,
name: res.name
}
this.pageData.locationObj = locationObj,
this.setData({ location: res.name })
}
})
},
1.5实现重置数据
点击reset按钮触发onReset方法,将数据置空
onReset: function(e) {
this.setData({
image:null,
address:null,
time:null,
location:null
})
}
2.查看所有任务模块
这是小程序的首页,能够从云数据库todos中获取任务数组task[],并封装getData方法在页面上以单元格组件展现,并实现下拉刷新功能。当点击单元格能跳转到对应的任务详情模块;当点击每个单元格前的○图标,能把当前任务状态由“未完成”改变成“已完成”,图标和数据库会有响应的改变;当点击右下方的加号按钮能跳转到待办任务添加模块;当点击右下方的叉号按钮能从云数据库中删除当前已完成的任务;
2.1.实现引入云数据库并获取数据
// pages/index/index.js
const db = wx.cloud.database();
const todos = db.collection("todos")
getData:function(callback){//封装获取数据方法
if(!callback){//如果callback不存在则自动生成一个空函数
callback = res => {}
}
wx.showLoading({
title: '数据加载中',
})
todos.get().then(res => {
this.setData({
tasks: res.data
}, res => {
wx.hideLoading();
callback();
})
})
}
2.2.实现下拉刷新和页面加载
onLoad: function (options) {
this.getData()
}
onPullDownRefresh: function () {
this.getData(res => {
wx.stopPullDownRefresh();
});
}
2.3.实现点击单元格能跳转到对应的任务详情模块
<van-cell
link-type="navigateTo"
url="../todoInfo/todoInfo?id={{item._id}}"
>
2.3.实现点击○改变任务状态
onChange(event) {//选中了一条新的数据
if (this.data.result.length < event.detail.length){
for(var i=0;i<event.detail.length;i++){
var isEquals = false;
for (var j = 0; j < this.data.result.length;j++) {
if (event.detail[i] == this.data.result[j]){
isEquals = true;
break;
}
}
if (!isEquals) {
todos.doc(event.detail[i]).update({
data: {
state: "已完成"
}
}).then(console.log).catch(console.error)
}
}
}
else {//取消勾选
for (var i = 0; i < this.data.result.length; i++) {
var isEquals = false;
for (var j = 0; j < event.detail.length; j++) {
if (this.data.result[i] == event.detail[j]) {
isEquals = true;
break;
}
}
if (!isEquals) {
todos.doc(this.data.result[i]).update({
data: {
state: "进行中"
}
}).then(console.log).catch(console.error)
}
}
}
this.setData({
result: event.detail
});
}
2.4.实现点击加号按钮跳转到待办任务添加模块
<navigator url="../addTodo/addTodo">
<van-icon name="add-square" class="addBtn" size="60px"/>
</navigator>
2.5.实现点击叉号按钮删除当前已完成的任务
delTodo:function(){
for (var i = 0; i < this.data.result.length; i++) {
todos.doc(this.data.result[i]).remove().then(res => {
this.setData({
result: []
})
this.getData()
}).catch(console.error)
}
},
3.任务详情模块
当点击任务单元格时,会跳转到详情页面。在详情页面可以看到任务的标题、状态、开始时间、图片(有则显示)、地址(有则显示)。当点击地址单元格能进入导航页面,实现导航功能。
3.1.实现在todoInfo.js文件中引入云数据库并获取数据
// pages/todoInfo/todoInfo.js
const db = wx.cloud.database();
const todos = db.collection("todos")
onLoad: function (options) {//option中有页面id
this.pageData.id = options.id
todos.doc(options.id).get().then(res => {
this.setData({
task:res.data
})
})
}
3.2.实现导航功能
为相应单元格绑定viewlocation事件,并在其中使用微信内置地图查看位置wx.openLocation(Object object)方法
viewlocation:function(){
wx.openLocation({
latitude:this.data.task.location.latitude,
longitude: this.data.task.location.longitude,
name:this.data.task.location.name,
address:this.data.task.location.address
})
},
小程序测试
1.测试待办任务添加模块功能
2.测试查看所有任务模块
3.测试任务详情模块
心得体会:
虽然在此之前并未接触过小程序开发,但是由于先前在课堂上学习了Java和安卓,课下自学了HTML、CSS和JavaScript,所以还是比较容易上手的。因为对后端了解不多,所以使用的是小程序云开发,帮我解决了很多搭建服务器和数据库存储等后端问题。总结一下自己在本次开发中吸取的教训:①因为自己的开发经验不足,虽然知道功能需求,但是设计逻辑有时会理不清,总是会删改代码,所以以后编写代码时,实现逻辑定要理清先才好。②使用微信设定好的模板框架时不要一股脑的全部粘贴复制,理解其中原理才能真正用好,不然只是填入参数,了解功能当遇到编译错误的时候就无从下手了。③很多变量赋值都会不小心写错,但是控制台有没有报错,这时候就需要设置断点进行单步调试,查看变量的变化情况是否如自己所想。④当代码检查无误仍然不能正常运行的时候,要考虑一些配置问题,例如是否安装了功能包?或者重复安装功能包?⑤当遇到自己不会写功能多去网上看别人发的教程贴,学习借鉴。没有什么功能是实现不了的。⑥还有代码的书写格式和命名规则一定要规范,自己写的代码自己看都觉得乱,别人更加难看懂了。