目前市面上提供了一些免费开源的第三方小程序UI组件库,可以下载后放到项目文件夹中直接使用,比起开发者从头开始自定义组件更为方便、高效。本次考虑使用第三方UI组件来实现界面的视觉统一。本次以有赞第三方UI组件库Vant Weapp为例,介绍如何使用自定义组件配合云开发中的数据库基本功能实现一个生日管家小程序。
本项目一共三个页面,即首页、好友信息编辑页和好友信息展示页。
首页功能需求:1.包含“添加新朋友”按钮、搜索框和好友列表。2.点击“添加新朋友”按钮后跳转到好友信息编辑页,可以录入数据。3.搜索框可以根据好友姓名关键词查找指定好友。4.好友生日列表需要展示好友姓名、生日、距离下个生日还有多少天,并且点击好友头像可以跳转到好友信息展示页查看详情。
好友信息编辑页功能需求:1.以表单的形式要求用户录入好友的姓名、性别、生日、电话、关系等信息。2.“保存记录”按钮用于添加或更新好友数据到云数据库中。3.“取消表单”按钮用于取消本次填写,返回上一页。
好友信息展示页面功能需求:1.顶端展示好友的头像和姓名。2.中间列表展示好友的性别、电话、和用户本人关系、距离出生已经多少天、距离下个生日还有多少天。3.下方是“修改”按钮和“删除”按钮,分别用于跳转编辑页面和直接删除当前好友。
一、部署云数据库
1.打开云开发控制台,创建一个新的数据集,例如birthday。
2.检查birthday数据集的权限,确认是“仅创建者及管理员可读写”。
二、创建页面文件
本项目有三个页面文件,分别是index(首页)、edit(好友信息编辑页)和detail(好友信息展示页)。打开app.json文件,在pages属性中追加edit和detail页面的路径描述,保存后pages文件夹下会自动生成后面的两个页面文件。注:须将app.json文件中的"style":"v2" 手动删除,这句代码是表示使用小程序新版的基础组件样式,会对当前的UI组件库的部分组件造成样式干扰。
三、创建其他文件
接下来创建其他自定义文件:images:用于存放图片素材,已存在;utils:用于存放公共JS文件,需要手动创建;vant-weapp:用于存放有赞UI库的dist目录,需要手动创建。
以上三步具体操作略。
四:界面及主要代码
1.首页
<!--index.wxml-->
<!-- 添加新朋友按钮 -->
<van-button block type='default' bindtap='addFriend'>添加新朋友</van-button>
<!-- 搜索区域 -->
<van-search placeholder="请输入搜索关键词" show-action bind:search="onSearch" bind:cancel="onCancel" />
<!-- 好友列表 -->
<block wx:for='{{friendsList}}' wx:key='{{item._id}}'>
<van-card centered desc="{{(item.date)}}" title="{{item.name}}" thumb-link='../detail/detail?id={{item._id}}&n2={{item.n}}' thumb="{{item.avatar}}">
<view slot="footer">
距离下个生日
<text style='color:red;font-weight:bold;'>{{item.n}}天</text>
</view>
</van-card>
</block>
//index.js
var utils = require('../../utils/utils.js')
const db = wx.cloud.database()
const birthday = db.collection('birthday')
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 自定义函数--添加好友信息
*/
addFriend: function(options) {
let id = 'new'
wx.navigateTo({
url: '../edit/edit?id=' + id
})
},
/**
* 自定义函数--取消搜索
*/
onCancel: function(e) {
//获取好友列表
this.getFriendsList()
},
/**
* 自定义函数--搜索关键词
*/
onSearch: function(e) {
//获取搜索关键词
let keyword = e.detail
//使用正则表达式模糊查询
birthday.where({
name: db.RegExp({
regexp: keyword,
options: 'i',
})
}).orderBy('date', 'asc').get({
success: res => {
this.processData(res.data)
}
})
},
/**
* 自定义函数--获取好友列表
*/
getFriendsList: function() {
//查找好友列表,按照出生日期升序排列
birthday.orderBy('date', 'asc').get({
success: res => {
this.processData(res.data)
}
})
},
/**
* 自定义函数--处理数据(计算距离下个生日天数)
*/
processData: function(list) {
for (var i = 0; i < list.length; i++) {
//获取不带年份的生日
let date = list[i].date
//计算相差几天
let n = utils.getNextBirthday(date)
list[i].n = n
}
this.setData({
friendsList: list
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function() {
//获取好友列表
this.getFriendsList()
},
})
index.json文件:
{
"usingComponents": {
"van-search": "/vant-weapp/dist/search/index",
"van-card": "/vant-weapp/dist/card/index",
"van-button": "/vant-weapp/dist/button/index"
}
}
2.好友信息编辑页
<!--pages/edit/edit.wxml-->
<form bindsubmit='onSubmit'>
<!-- 第1行 -->
<van-row>
<van-col span="6">
<label>姓名</label>
</van-col>
<van-col span="18">
<input name='name' placeholder='请输入姓名' value='{{info.name}}'></input>
</van-col>
</van-row>
<!-- 第2行 -->
<van-row>
<van-col span="6">
<label>性别</label>
</van-col>
<van-col span="18">
<radio-group name='gender'>
<radio color='#DE6E6D' value='1' checked='{{info.gender==1}}' />男
<radio color='#DE6E6D' value='2' checked='{{info.gender==2}}' />女
</radio-group>
</van-col>
</van-row>
<!-- 第3行 -->
<van-row>
<van-col span="6">
<label>生日</label>
</van-col>
<van-col span="18">
<picker name='birthday' mode='date' bindchange='dateChange' value='{{date}}'>
<view>{{date}}</view>
</picker>
</van-col>
</van-row>
<!-- 第4行 -->
<van-row>
<van-col span="6">
<label>电话</label>
</van-col>
<van-col span="18">
<input name='tel' type='number' placeholder='请输入联系电话' value='{{info.tel}}'></input>
</van-col>
</van-row>
<!-- 第5行 -->
<van-row>
<van-col span="6">
<label>关系</label>
</van-col>
<van-col span="18">
<input name='relationship' placeholder='描述你们的关系' value='{{info.relationship}}'></input>
</van-col>
</van-row>
<!-- 第6行 -->
<van-row>
<van-col span="18" offset="3">
<button form-type='submit'>保存记录</button>
</van-col>
<van-col span="18" offset="3">
<button bindtap='cancelEdit'>取消修改</button>
</van-col>
</van-row>
</form>
// pages/edit/edit.js
const db = wx.cloud.database()
const birthday = db.collection('birthday')
Page({
/**
* 页面的初始数据
*/
data: {
date: '点击设置生日'
},
/**
* 自定义函数--更新页面上显示的出生日期
*/
dateChange: function(e) {
this.setData({
date: e.detail.value
})
},
/**
* 自定义函数--提交表单数据
*/
onSubmit: function(e) {
//获取表单中提交的全部数据
let info = e.detail.value
//追加一个不带年份的生日信息
let date = info.birthday.substring(5)
info.date = date
// 获取好友id
let id = this.data.id
// 添加新朋友
if (id == 'new') {
//随机选择一个头像
let i = Math.ceil(Math.random() * 9)
info.avatar = '/images/avatar/00' + i + '.jpg'
// 往云数据库中添加当前好友信息
birthday.add({
data: info,
success: res => {
// 成功后返回首页
wx.navigateBack()
},
fail: err => {
// 失败提示
wx.showToast({
title: '保存失败',
})
}
})
}
// 好友已存在
else {
// 根据好友id更新数据
birthday.doc(id).update({
data: info,
success: res => {
// 成功后返回上一页
wx.navigateBack()
},
fail: err => {
// 失败提示
wx.showToast({
title: '保存失败',
})
}
})
}
},
/**
* 自定义函数--取消修改并返回上一页
*/
cancelEdit: function() {
wx.navigateBack()
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
// 获取携带的参数id
let id = options.id
// 更新id数据
this.setData({
id: id
})
// 如果好友已存在
if (id != 'new') {
// 根据好友id从云数据库获取好友信息
birthday.doc(id).get({
success: res => {
this.setData({
info: res.data,
date: res.data.birthday
})
}
})
}
},
})
edit.json文件:
{
"usingComponents": {
"van-row": "/vant-weapp/dist/row/index",
"van-col": "/vant-weapp/dist/col/index"
}
}
3.好友信息展示页
<!--pages/detail/detail.wxml-->
<!-- 顶部头像和姓名 -->
<view class='avatarBox'>
<image src='{{info.avatar}}'></image>
<view>{{info.name}}</view>
</view>
<!-- 个人信息展示 -->
<van-cell-group>
<van-cell title="性别" value="{{info.gender==1?'男':'女'}}" />
<van-cell title="生日" value="{{info.birthday}}" />
<van-cell title="电话" value="{{info.tel}}" />
<van-cell title="关系" value="{{info.relationship}}" />
<van-cell title="距离出生已经" value="{{n1}}天" />
<van-cell title="距离下个生日还有" value="{{n2}}天" />
</van-cell-group>
<!-- 按钮区域 -->
<van-button block type='warning' bindtap='editFriend'>修改</van-button>
<van-button block type='danger' bindtap='deleteFriend'>删除</van-button>
// pages/detail/detail.js
const utils = require('../../utils/utils.js')
const db = wx.cloud.database()
const birthday = db.collection('birthday')
Page({
/**
* 自定义函数--编辑好友信息
*/
editFriend: function() {
//获取当前好友id
let id = this.data.id
//跳转到编辑页面并带参数id
wx.navigateTo({
url: '../edit/edit?id=' + id
})
},
/**
* 自定义函数--删除好友
*/
deleteFriend: function() {
//获取当前好友id
let id = this.data.id
//删除当前好友
birthday.doc(id).remove({
success: res => {
//删除成功后返回上一页
wx.navigateBack()
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
//获取从首页传来的参数
let id = options.id//好友id
let n2 = options.n2//距离下个生日天数
//更新页面数据
this.setData({
id: id,
n2: n2
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function() {
//获取当前好友id
let id = this.data.id
//从云数据库查找当前好友信息
birthday.doc(id).get({
success: res => {
//获取当前日期
let today = utils.getToday()
//获取当前年份
let y = utils.getFullYear()
//获取生日(带年份)
let b_day = res.data.birthday
//计算距离出生的天数
let n1 = utils.dateDiff(b_day, today)
//更新页面数据
this.setData({
info: res.data,
n1: n1
})
}
})
},
})
detail.json文件:
{
"usingComponents": {
"van-button": "/vant-weapp/dist/button/index",
"van-cell": "/vant-weapp/dist/cell/index",
"van-cell-group": "/vant-weapp/dist/cell-group/index"
}
}
4.其他代码:
utils.js文件:
//获取当前格式化日期
function getToday(){
//获取当前日期对象
var now = new Date()
//获取当前年份(4位数)
var y = now.getFullYear()
//获取当前月份
var m = now.getMonth() + 1
//获取当前日期
var d = now.getDate()
//格式化当天日期
var today = y + '/' + m + '/' + d
return today
}
//获取当前年份(4位数)
function getFullYear() {
//获取当前日期对象
var now = new Date()
//获取当前年份(4位数)
var y = now.getFullYear()
return y
}
//计算天数差
function dateDiff(sDate1, sDate2) {
sDate1 = sDate1.replace(/-/g, '/')
sDate2 = sDate2.replace(/-/g, '/')
var oDate1 = new Date(sDate1)
var oDate2 = new Date(sDate2)
var iDays = parseInt((oDate2 - oDate1) / 1000 / 3600 / 24)
//把相差的毫秒数转换为天数
return iDays
}
//计算距离下个生日还有多少天
function getNextBirthday(b_day) {
//获取当前日期
var today = getToday()
//获取当前年份
var y = getFullYear()
//计算日期差
var n = dateDiff(today, y + '-' + b_day)
//今年生日已经过完了
if (n < 0) {
//获得明年年份
y++
//计算日期差
n = dateDiff(today, y + '-' + b_day)
}
return n
}
module.exports = {
getToday:getToday,
getFullYear:getFullYear,
dateDiff: dateDiff,
getNextBirthday: getNextBirthday
}
还有其他代码略。
小知识:onLoad()函数在页面第一次加载时触发,从跳转页面返回时不触发,可以传递参数。
onShow()函数在页面显示时调用,可多次调用 ,不能传递参数。
某页面同时有onLoad()和onShow()函数时,该页面第一次加载时onLoad()函数会先于onShow()执行;页面切换时onShow()会先于onLoad()执行。