
自2020年以来,在疫情的影响下,越来越多的活动选择了线上进行。各式各样的微信小程序也出现在了我们生活的方方面面中。本篇将介绍使用微信小程序实现发起一个活动报名的设计,以此为基础,我们可以掌握微信小程序表单的基本用法,进而在诸如疫情信息登记、出入报备等场景中使用小程序进行开发,满足相关的需求。
设计如图 1所示的页面,实现输入活动名称、设定活动的开始/结束/报名截止时间、在地图上选择活动地点、输入活动简介和活动参与人数上限以及根据费用的情况来判断是否允许用户上传微信收款二维码。注意需要对输入的时间进行校验,以及给予必要的交互提示。

▍图1 发起新活动
本文以发起活动报名为示例场景,涉及小程序表单文本组件、选择器组件、地图组件的使用。同时要求对输入的数据进行合法性校验,又综合了小程序事件处理、选择渲染等内容。掌握此案例,可以较好地泛化学习其余表单的类似用法。
页面加载时,即会默认显示当前时间,以活动开始时间为例,页面的onLoad函数如下:
- //newactivity.js
- onLoad () {
- this.setData({
- acStartDate:util.formatDate(),
- acStartTime: util.formatTime(),
- acEndDate:util.formatDate(),
- acEndTime: util.formatTime(),
- signEndDate: util.formatDate(),
- signEndTime: util.formatTime(),
- });
- },
其中,util.formatDate(),util.formatTime()来自自定义的公共函数。主要功能是将Unix的时间戳格式化成标准的年月日时分秒的格式。
在前端以开始时间部分为例,代码如下:
- <!--newactivity.wxml-->
- <view>
- <view>
- <text >开始时间</text>
- </view>
- <picker name="acStartDate" mode="date" start="2000-01-01" end="2100-12-31" value="{{acStartDate}}" bindchange="acStartDateChange">
- <view >
- {{acStartDate}}
- </view>
- </picker>
- <picker name="acStartTime" mode="time" start="00:00" end="23:59" value="{{acStartTime}}" bindchange="acStartTimeChange">
- <view >
- {{acStartTime}}
- </view>
- </picker>
- </view>
日期和时间分别是两个带有默认值的picker组件,每个picker组件还绑定了对应的change事件,用于获取设定的值。以acStartDateChange函数为例,函数内容如下:
- acStartDateChange:function(e){
- console.log('开始日期',e.detail.value);
- this.setData({
- acStartDate:e.detail.value,
- signEndDate:e.detail.value,
- acEndDate:e.detail.value,
- });
- },
改变开始日期的同时,也会改变活动结束日期和报名截止日期,减少用户调节的次数。
为了确保时间的合法性,在修改活动结束时间以及报名截止时间时,均会在响应change事件的函数中执行检测时间的函数,不合法的话,就会重设当前值。在用户最后点击“确认发起活动”时,也会在form表单组件绑定响应submit事件的函数中执行响应的检测。
检测时间的函数如下:
- checkDateTime:function(){
- var result = new Object();
- var acStartDateTimeString = this.data.acStartDate + ' ' + this.data.acStartTime;
- var acStartDateTime = new Date(acStartDateTimeString);
- var acEndDateTimeString = this.data.acEndDate + ' ' + this.data.acEndTime;
- var acEndDateTime = new Date(acEndDateTimeString);
- var signEndDateTimeString = this.data.signEndDate + ' ' + this.data.signEndTime;
- var signEndDateTime = new Date(signEndDateTimeString);
- var nowDateTimeString = util.formatDate()+' '+util.formatTime();
- var nowDateTime = new Date(nowDateTimeString);
- if (acEndDateTime <= acStartDateTime) {
- result.status = false;
- result.data = "活动的结束时间必须晚于活动的开始时间!";
- } else if (signEndDateTime > acEndDateTime) {
- result.status = false;
- result.data = "报名的截止时间不能晚于活动的结束时间!"
- } else if(signEndDateTime<nowDateTime){
- result.status = false;
- result.data = "报名的截止时间不能早于当前时间!"
- }else {
- result.status = true;
- }
- if(!result.status){
- wx.showModal({
- title: '时间填写错误',
- content: result.data,
- showCancel:false,
- confirmText:'返回修改'
- })
- }
- console.log('判断结果是',result);
- return result;
- },
在点击“地点”的输入框时,小程序会调用地图组件,根据用户定位或者在地图上的选点,获取地理位置信息。为此,需要为input组件绑定focus事件。示例如下:
- <!--newactivity.wxml-->
- <view >
- <text >地点</text>
- </view>
- <view >
- <input bindfocus="chooseLocation" name="placeName" placeholder="点击在地图上选择位置" type="text" value="{{placeName}}"/>
- </view>
在chooseLocation函数中,再调用微信的wx.chooseLocation接口,打开地图选点,将获取到的经纬度等地理位置信息赋值给页面的data属性。示例如下:
- //newactivity.js
- chooseLocation:function(e){
- var self = this;
- wx.chooseLocation({
- success: function(res) {
- self.setData({
- placeName: res.name,
- longitude:res.longitude,
- latitude:res.latitude
- })
- },
- })
- },
在页面上输入活动费用信息时,会根据当前输入的值的大小,判断是否应该出现上传图片的组件,如图2 所示。


▍图2 没有费用(左)和有费用(右)
实现过程主要是通过监听费用input组件的input事件,判断输入的值大小,依据值与0的大小关系,改变一个用来标识上传图片组件显示状态的变量的值,来动态显示/隐藏上传图片组件。
示例如下:
- <!--newactivity.wxml-->
- <input name="fee" placeholder="¥/人" bindinput="showUpload" type="digit"/>
-
- <view hidden="{{show>0? false:true}}" >
- <view>
- <block wx:if="{{imageSrc}}">
- <image src="{{imageSrc}}" class="image" bindtap="chooseImage" mode="aspectFit"></image>
- <view>点击图片可重新上传</view>
- </block>
- <block wx:else>
- <view bindtap="chooseImage">
- <view></view>
- <view></view>
- </view>
- <view>请上传您的个人微信收款二维码图片</view>
- </block>
- </view>
- </view>
-
- //newactivity.js
- showUpload:function(e){
- this.setData({
- show:e.detail.value
- })
- console.log("费用输入的数字是:",this.data.show);
- },
showUpload函数将会通过判断输入的值,来改变变量show的值,进而改变前端中的hidden属性,从而实现了上传图片组件的动态显示/隐藏。
在上传图片后,该区域需要显示出上传的图片内容,如图3所示。

▍图3 成功上传图片
该功能主要是通过绑定的tap事件函数chooseImage实现的。chooseImage函数还实现了上传文件到服务器的功能。内容如下:
- //newactivity.js
- chooseImage: function() {
- var self = this
- wx.chooseImage({
- count: 1,
- sizeType: ['original '],
- sourceType: ['album'],
- success: function(res) {
- console.log('chooseImage success, temp path is', res.tempFilePaths[0])
- var imageSrc = res.tempFilePaths[0]
- wx.showLoading({
- title: '正在上传',
- })
- wx.uploadFile({
- url: self.data.uploadFileUrl,
- filePath: imageSrc,
- name: 'feePic',
- success: function(res) {
- console.log('uploadImage success, res is:', res.data)
- var obj = JSON.parse(res.data);
- console.log('转换后的json对象为:',obj);
- if (obj.status == true){
- wx.hideLoading();
- wx.showToast({
- title: '上传成功',
- icon: 'success',
- duration: 1000
- })
- self.setData({
- imageSrc,
- feePicId:obj.data
- })
- }else{
- wx.hideToast();
- wx.showModal({
- title: '上传文件失败',
- content: obj.data,
- })
- }
- },
- fail: function({errMsg}) {
- console.log('uploadImage fail, errMsg is', errMsg)
- }
- })
-
- },
- fail: function({errMsg}) {
- console.log('chooseImage fail, err is', errMsg)
- }
- })
- }
- }
提交表单,是通过form组件的submit事件绑定的addNewActivity函数实现的。在addNewActivity函数中,会通过checkLegal函数对所有表单项进行合法性校验,并访问设定的后端服务器链接,得到服务器返回的结果后,带着活动ID参数跳转到分享活动页面。内容如下:
- //newactivity.js
- addNewActivity:function(e){
- var result = this.checkLegal(e);//检查表单项
- if(!result.status){
- wx.showModal({
- title: '填写信息错误',
- content: result.data,
- showCancel:false,
- confirmText:'返回修改',
- success: function (res) {
- if (res.confirm) {
- console.log('用户点击确定')
- } else if (res.cancel) {
- console.log('用户点击取消')
- }
- }
- })
- }else{
- console.log(result.data);
- wx.showLoading({
- title: '请稍等',
- })
- qcloud.request({//小程序SDK的带有登录请求的网络请求接口
- login:true,//携带用户登录信息
- url: this.data.requestUrl,//访问服务器地址
- data:result.data,
- success:function(res){
- if(res.data.code == 1){
- wx.hideLoading();
- wx.showToast({
- title: '创建活动成功',
- icon:'success',
- duration:1500
- })
- console.log("创建的活动ID为:",res.data.id);
- setTimeout(function () {
- wx.redirectTo({
- url: '../shareactivity/shareactivity?id=' + res.data.id,//带新建活动ID跳转
- })
- }, 1500)
- }
- }
- })
- }
- },