3.2 编写一个子表单
子表单的界面如下图所示,包括租赁人的姓名、电话、身份证和人脸信息。
简单分析一下界面,第一行是一个静态文本,即 请登记从租客 N 的信息
,和一个删除按钮,这个直接使用循环编译语法读取下标即可。
代码如下所示。
<view class="weui-cells__title tishi"> 请登记从租客 N 的信息: <button type="warn" size="mini" class='buttomm' bindtap="deleteCongItem">删除</button> </view>
第二行是姓名表单,普普通通的一个输入框即可。
<view class="weui-cell weui-cell_active hang"> <view class="weui-cell__hd"><label class="weui-label">姓名</label></view> <view class="weui-cell__bd"> <input class="weui-input" placeholder="从租客姓名" bindblur="lesseeName2" value="张三" placeholder-class="weui-input__placeholder" /> </view> </view>
第三行是电话表单,也是普普通通的一个输入框即可。
<view class="weui-cell weui-cell_active hang"> <view class="weui-cell__hd"><label class="weui-label">电话</label></view> <view class="weui-cell__bd"> <input class="weui-input" placeholder="从租客电话" bindblur="lesseeMobile2" value="17800000001" placeholder-class="weui-input__placeholder" /> </view> </view>
第四行是身份证表单,更是普普通通的一个输入框即可。
<view class="weui-cell weui-cell_active hang"> <view class="weui-cell__hd"><label class="weui-label">身份证</label></view> <view class="weui-cell__bd"> <input class="weui-input" placeholder="从租客身份证" bindblur="lesseeCard2" value="330200200001010000" placeholder-class="weui-input__placeholder" /> </view> </view>
前面三个输入型表单,都需要将用户输入的值绑定到某个变量,这时就需要用到一个变化监听事件。
如身份证的 input 表单中,有 bindblur="lesseeCard2"
的属性复制,也就是当这个输入框的数据发生变化时,会执行 lesseeCard2
事件。
lesseeCard2: function (e) { this.setData({ lesseeCard2: e.detail.value }) },
这样就可以间接实现数据的双向绑定。
第五行是人脸上传,这是一个文件上传,可以分为上传按钮和上传图片的预览框,界面代码如下图所示。
<view class='upload_img'> <view class='upload_img_btn'> <view class='title'> <view class='shu'></view> <text>人脸</text> </view> <button type="primary" bindtap="chooseImageItem" data-itemid="{{idx}}" class='btn'>添加</button> </view> <view wx:if="{{item.photo != ''}}" class='img_box' id='imgs' style='display:flex;justify-content: space-between;padding-top:10px;'> <view class="q-image-wrap imgs"> <image class="q-image" src="{{item.photo}}" mode="aspectFit" data-idx="{{item.photo}}" bindtap="handleImagePreviewItem"></image> <view class="q-image-remover delete" data-idx="{{idx}}" bindtap="removeImageItem">删除</view> </view> </view> </view>
上传后的预览效果如下图所示。
在用户点击 添加
按钮时,触发 chooseImageItem
方法,调用系统的相册选择,代码如下图所示。
chooseImageItem: function (e) { var that = this; var itemId = e.currentTarget.dataset.itemid; wx.chooseImage({ sizeType: ['compressed'], //可选择原图或压缩后的图片 sourceType: ['camera'], // sourceType: ['album', 'camera'], //可选择性开放访问相册、相机 success: res => { console.log(res.tempFilePaths); console.log(res.tempFilePaths[0]); that.uploadImageItem(res.tempFilePaths[0], itemId); } }) },
其中 uploadImageItem
是自己实现的上传图片方法,即将用户上传到微信的临时性图片持久化存储到自己的业务系统,最终返回一个图片网址(即字符串,回写到图片数组中)。
uploadImageItem(e, itemId) { var that = this; wx.uploadFile({ url: app.data.appUrl + '/upload/uploadAppletImages?g=api&m=banana&a=upload_info', filePath: e, method: 'GET', name: 'file', header: { "Content-Type": "application/x-www-form-urlencoded", 'accessToken': app.data.token }, success: function (res) { console.log(JSON.parse(res.data)); var imageUrl = JSON.parse(res.data).result; if(imageUrl == undefined) { imageUrl = res.data.result; } var list = that.data.congList; list[itemId].photo = imageUrl; console.log(list); that.setData({ congList: list }) }, fail: function (res) { console.log(res); }, }) },
3.3 使用 wx:for 语法实现循环渲染
在 Vue
中可以使用 v-for
实现循环渲染,在微信小程序中也一样可以。
在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。
比如有一个租客数组 leaveList
,其中姓名字段为 name,就可以这么去表示。
<view wx:for="{{leaveList}}"> 租客{{index}}: {{item.name}} </view>
我们可以用 wx:for-item
可以指定租赁数组当前元素的别名,下面的代码执行效果等同于上面。
<view wx:for="{{leaveList}}" wx:for-item="myItem"> 租客{{index}}: {{myItem.name}} </view>
我们可以用 wx:for-index
可以指定数组当前下标的变量名,下面的代码执行效果等同于上面。
<view wx:for="{{leaveList}}" wx:for-index="myIndex"> 租客{{myIndex}}: {{item.name}} </view>
另外在循环渲染时还需要提供一个 wx:key
,文档说明如下。
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略
所以我们需要改造成这样:
<view wx:for="{{leaveList}}" wx:key="index"> 租客{{index}}: {{item.name}} </view>
我们最终的目标是实现从租客的循环渲染,所以只需要在第二步的代码上套一层循环,代码如下所示。
<view class="box" wx:for="{{congList}}" wx:for-item="item" wx:for-index="idx" wx:key="idx"> <view class="weui-cells__title tishi"> 请登记从租客{{idx + 1}}的信息: <button type="warn" size="mini" class='buttomm' bindtap="deleteCongItem" data-idx="{{idx}}">删除</button> </view> <!-- 开始 --> <view class="weui-cell weui-cell_active hang"> <view class="weui-cell__hd"><label class="weui-label">姓名</label></view> <view class="weui-cell__bd"> <input class="weui-input" placeholder="从租客姓名" data-itemid="{{idx}}" bindblur="lesseeName2" value="{{item.lesseeName}}" placeholder-class="weui-input__placeholder" /> </view> </view> <!-- 结尾 --> <!-- 开始 --> <view class="weui-cell weui-cell_active hang"> <view class="weui-cell__hd"><label class="weui-label">电话</label></view> <view class="weui-cell__bd"> <input class="weui-input" placeholder="从租客电话" data-itemid="{{idx}}" bindblur="lesseeMobile2" value="{{item.lesseeMobile}}" placeholder-class="weui-input__placeholder" /> </view> </view> <!-- 结尾 --> <!-- 开始 --> <view class="weui-cell weui-cell_active hang"> <view class="weui-cell__hd"><label class="weui-label">身份证</label></view> <view class="weui-cell__bd"> <input class="weui-input" placeholder="从租客身份证" data-itemid="{{idx}}" bindblur="lesseeCard2" value="{{item.lesseeCard}}" placeholder-class="weui-input__placeholder" /> </view> </view> <!-- 结尾 --> <view class='upload_img'> <view class='upload_img_btn'> <view class='title'> <view class='shu'></view> <text>人脸</text> </view> <button type="primary" bindtap="chooseImageItem" data-itemid="{{idx}}" class='btn'>添加</button> </view> <view wx:if="{{item.photo != ''}}" class='img_box' id='imgs' style='display:flex;justify-content: space-between;padding-top:10px;'> <view class="q-image-wrap imgs"> <image class="q-image" src="{{item.photo}}" mode="aspectFit" data-idx="{{item.photo}}" bindtap="handleImagePreviewItem"></image> <view class="q-image-remover delete" data-idx="{{idx}}" bindtap="removeImageItem">删除</view> </view> </view> </view> </view>
对于数据的双向绑定,以姓名为例,代码如下所示。
<view class="weui-cell weui-cell_active hang"> <view class="weui-cell__hd"><label class="weui-label">姓名</label></view> <view class="weui-cell__bd"> <input class="weui-input" placeholder="从租客姓名" data-itemid="{{idx}}" bindblur="lesseeName2" value="{{item.lesseeName}}" placeholder-class="weui-input__placeholder" /> </view> </view>
使用 data-itemid="{{idx}}"
语法,可以将当前下标值作为 itemid
参数,传到 lesseeName2
事件中,事件的代码如下所示。
lesseeName2: function (e) { console.log(e); var itemId = e.currentTarget.dataset.itemid; var list = this.data.congList; list[itemId].lesseeName = e.detail.value; this.setData({ congList: list }) },
首先根据下标读取到当前子表单的数据,然后赋值,最后再会写,完成双向数据绑定操作。
3.4 表单提交
当表单的数据全部输入完成,也绑定到相应的变量后,就可以对表单数据进行提交,由后端持久化到数据库。
对于提交按钮,只是一个普普通通的按钮,一行代码即可。
<button type="primary" bindtap="addTenant" loading="{{submitLoading}}" disabled="{{submitLoading}}" class='weui-btn weui-btn_primary'>提交</button>
用户点击提交按钮后,首先需要对数据进行判空,如果没问题了直接传到 API 接口,继续下步的业务逻辑,相关代码如下所示。
addTenant: function () { var that = this; if (that.data.lesseeName == '') { wx.showToast({ title: '租赁人姓名为空', icon: "none" }) } else if (that.data.lesseeMobile == '') { wx.showToast({ title: '租赁人电话为空', icon: "none" }) } else if (that.data.lesseeCard == '') { wx.showToast({ title: '租赁人身份证为空', icon: "none" }) } else if (that.data.images2.length < 1) { wx.showToast({ title: '请上传租客人脸', icon: "none" }) } else { that.setData({ submitLoading: true }) wx.showLoading({}); var form = {}; form.lesseeName = that.data.lesseeName; form.lesseeMobile = that.data.lesseeMobile; form.lesseeSex = that.data.sexList[that.data.sexIndex]; form.mainFlag = that.data.mainList[that.data.mainIndex]; form.lesseeCard = that.data.lesseeCard; form.province = that.data.province; form.city = that.data.city; form.county = that.data.county; form.lesseeAddress = that.data.lesseeAddress; form.workUnit = that.data.workUnit; form.address = that.data.address; form.roomId = that.data.roomId; form.registerDate = that.data.registerDate; form.outDate = that.data.outDate; form.photo = that.data.images2[0]; form.leaseContract = that.data.images[0]; form.remark = that.data.remark; form.roomId = that.data.roomId; form.auditMessage = JSON.stringify(this.data.congList); wx.request({ url: app.data.appUrl + '/leaseRecord/insertOnApp', method: 'POST', data: form, header: { "Content-Type": "application/x-www-form-urlencoded", 'accessToken': app.data.token }, success(res) { console.log(res); if (res.data.success) { that.setData({ errMsg: "" }) wx.showModal({ title: "登记成功", content: "租客登记成功,请等待审核!是否返回房间页面?", success() { if (res.confirm) { } else { wx.navigateBack({ delta: 1, }) } } }) } else { that.setData({ errMsg: res.data.message }) wx.showToast({ title: "添加失败", icon: "error" }) } }, complete: function () { wx.hideLoading(); that.setData({ submitLoading: false }) } }) } },
4 总结
本文将介绍如何使用微信小程序编写动态表单,最终实现房屋租赁系统中多租客录入的业务。
业务驱动式学习是一种高效的学习方法,希望同学们不要只埋头于技术上,多多关注一些业务场景,因为业务和技术同等重要!