当前位置:   article > 正文

微信小程序的动态表单,实现房屋租赁的多租客录入_小程序动态表单

小程序动态表单

0 前言

本文将介绍如何使用微信小程序编写动态表单,最终实现房屋租赁系统多租客录入的业务。

在阅读本文前,您需要对微信小程序的开发有一个初步的了解,以便更容易的学会开发动态表单

作者主页Designer 小郑
作者简介:浙江某公司软件工程师,负责开发管理公司OA、CRM业务系统,全栈领域优质创作者,CSDN学院、蓝桥云课认证讲师,开发过20余个前后端分离实战项目,主要发展方向为Vue、SpringBoot、微信小程序,期待你我共同成长!
主打方向:Vue、SpringBoot、微信小程序

在这里插入图片描述


在这里插入图片描述


1 什么是表单

表单是一种数据采集工具,可以用来收集或呈现数据或者特定字段,可运用到不同的业务场景中,如调查问卷等。

简单来说,表单就是收集用户数据的主要方式,通过在线采集信息并且一键生成想要的数据,如下图所示。

在这里插入图片描述
还有一个概念是表格,表格和表单有着一定的区别和联系。

  • 表单:主要用于搜集信息。

  • 表格:主要用来存放数据。

当然还有更加花里胡哨的表单,一些主流的组件库都支持单选框、多选框、下拉选择框、开关、滑块等表单组件,如下图所示。

在这里插入图片描述

2 何为动态表单

动态表单顾名思义就是动态的表单,也就是表单的个数不是固定的,而是由具体的业务去决定。

比如对于一个房屋租赁系统,在登记某个房间的租客数据时,甲方往往会要求在一个界面中完成所有租客数据的登记,如下图所示。
在这里插入图片描述

用户添加完成主租客后,还需要录入从租客的数据,并且从租客的数量不固定

我们点击了“新增从租客”按钮,系统自动渲染出一个子表单界面,如下图所示。

在这里插入图片描述
再次点击,继续新增,如下图所示。

在这里插入图片描述
再次点击,继续新增,如下图所示。

在这里插入图片描述

如果添加多了,还需要可以点击每一个子表单的删除按钮,实现局部删除,如下图所示。

在这里插入图片描述


3 动态表单的实现

实现上面介绍的动态表单,总体来说分为以下三个步骤

  • 编写添加按钮
  • 编写一个子表单
  • 使用 wx:for 语法实现循环渲染
  • 表单提交

接下来我们逐一讲解。

在这里插入图片描述


3.1 编写添加按钮

第一步非常简单,新建一个按钮即可,界面代码如下所示。

<button type="primary" bindtap="addCongItem" class='weui-btn weui-btn_primary'>新增从租客</button>
  • 1

在实现动态表单之前首先建立一个数组变量,如下所示。

const app = getApp();
Page({
    data: {
        congList: []
    },
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

点击按钮后,我们需要初始化一个子表单界面,也就是 new 一个 item 子项,其中表单的房间 ID、起租时日期、终止日期要被初始化,如下所示。


addCongItem() {
    var newDate = new Date();
    var item = {
        lesseeName: "",
        lesseeMobile: "",
        lesseeCard: "",
        photo: "",
        registerDate: newDate.getFullYear() + "-" + (newDate.getMonth() < 9 ? "0" + (newDate.getMonth() + 1) : (newDate.getMonth() + 1)) + "-" + (newDate.getDate() < 10 ? "0" + newDate.getDate() : newDate.getDate()),
        outDate: (newDate.getFullYear() + 1) + "-" + (newDate.getMonth() < 9 ? "0" + (newDate.getMonth() + 1) : (newDate.getMonth() + 1)) + "-" + (newDate.getDate() < 10 ? "0" + newDate.getDate() : newDate.getDate()),
        roomId: JSON.parse(app.data.addRoomObj)
    };
    var list = this.data.congList;
    list.push(item);
    this.setData({
        congList: list
    })
    console.log(this.data.congList);
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

3.2 编写一个子表单

子表单的界面如下图所示,包括租赁人的姓名、电话、身份证和人脸信息。

在这里插入图片描述

简单分析一下界面,第一行是一个静态文本,即 请登记从租客 N 的信息,和一个删除按钮,这个直接使用循环编译语法读取下标即可。

代码如下所示。

<view class="weui-cells__title tishi">
    请登记从租客 N 的信息:
    <button type="warn" size="mini" class='buttomm' bindtap="deleteCongItem">删除</button>
</view>
  • 1
  • 2
  • 3
  • 4

第二行是姓名表单,普普通通的一个输入框即可。

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第三行是电话表单,也是普普通通的一个输入框即可。

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第四行是身份证表单,更是普普通通的一个输入框即可。

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

前面三个输入型表单,都需要将用户输入的值绑定到某个变量,这时就需要用到一个变化监听事件

如身份证的 input 表单中,有 bindblur="lesseeCard2" 的属性复制,也就是当这个输入框的数据发生变化时,会执行 lesseeCard2 事件。

    lesseeCard2: function (e) {
        this.setData({
            lesseeCard2: e.detail.value
        })
    },
  • 1
  • 2
  • 3
  • 4
  • 5

这样就可以间接实现数据的双向绑定。

第五行是人脸上传,这是一个文件上传,可以分为上传按钮和上传图片的预览框,界面代码如下图所示。

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

上传后的预览效果如下图所示。

在这里插入图片描述

在用户点击 添加 按钮时,触发 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);
        }
    })
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

其中 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);
        },
    })
},
  • 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

3.3 使用 wx:for 语法实现循环渲染

Vue 中可以使用 v-for 实现循环渲染,在微信小程序中也一样可以。

在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。

默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。

比如有一个租客数组 leaveList,其中姓名字段为 name,就可以这么去表示。

<view wx:for="{{leaveList}}">
  租客{{index}}: {{item.name}}
</view>
  • 1
  • 2
  • 3

我们可以用 wx:for-item 可以指定租赁数组当前元素的别名,下面的代码执行效果等同于上面。

<view wx:for="{{leaveList}}" wx:for-item="myItem">
  租客{{index}}: {{myItem.name}}
</view>
  • 1
  • 2
  • 3

我们可以用 wx:for-index 可以指定数组当前下标的变量名,下面的代码执行效果等同于上面。

<view wx:for="{{leaveList}}" wx:for-index="myIndex">
  租客{{myIndex}}: {{item.name}}
</view>
  • 1
  • 2
  • 3

另外在循环渲染时还需要提供一个 wx:key,文档说明如下。

如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略

所以我们需要改造成这样:

<view wx:for="{{leaveList}}" wx:key="index">
  租客{{index}}: {{item.name}}
</view>
  • 1
  • 2
  • 3

我们最终的目标是实现从租客的循环渲染,所以只需要在第二步的代码上套一层循环,代码如下所示。

<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>
  • 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

对于数据的双向绑定,以姓名为例,代码如下所示。

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

使用 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
    })
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

首先根据下标读取到当前子表单的数据,然后赋值,最后再会写,完成双向数据绑定操作。


3.4 表单提交

当表单的数据全部输入完成,也绑定到相应的变量后,就可以对表单数据进行提交,由后端持久化到数据库。
在这里插入图片描述

对于提交按钮,只是一个普普通通的按钮,一行代码即可。

<button type="primary" bindtap="addTenant" loading="{{submitLoading}}" disabled="{{submitLoading}}" class='weui-btn weui-btn_primary'>提交</button>
  • 1

用户点击提交按钮后,首先需要对数据进行判空,如果没问题了直接传到 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
                })
            }
        })
    }
},
  • 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

4 总结

本文将介绍如何使用微信小程序编写动态表单,最终实现房屋租赁系统多租客录入的业务。

业务驱动式学习是一种高效的学习方法,希望同学们不要只埋头于技术上,多多关注一些业务场景,因为业务和技术同等重要!

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/131783
推荐阅读
相关标签
  

闽ICP备14008679号