当前位置:   article > 正文

动态表单的实现和校验

动态表单的实现和校验

需求

在用户下单过程中,需要填写用户信息,包括:姓名,手机号,身份证号,邮箱等。这部分需要填写的内容由后端进行配置,可能只需要填写姓名+手机号。可能需要填写姓名+手机号+身份证号。后端配置的内容包含输入框标题text和输入框的key,用户个数可以添加,新增的用户同样满足后端配置的填写表单要求。

思考逻辑

我们面对这个需求,可以想到的是首先把表单写成固定的表单,然后根据后端配置进行判断展示,但是这样对于后端配置的text和key就不能很好适配。
那我们考虑把text和key需要变成一个变量运用起来。
现在还有一个问题就是在于表单内容类型,包含普通输入框text,数字输入框number,身份证号输入框idcard带图片识别身份证号功能。
有这么多种类型的输入框,我们首先需要考虑将所有的输入框类型集合到一个输入框组件中。外部传递一个类型type,我们就返回对应的输入框。
然后对于后端配置的内容,我们根据它们返回的格式为data:[{text:“XXX”,key:“XXX”}]。我们需要对data进行循环再展示。

代码展示

输入框组件
components/PersonInput.vue
<template>
  <view class="conter">
      <view class="label">
        {{ label }}
      </view>
      <view>
        <input
          v-if="type === 'text'"
          :type="type"
          :value="inputVal"
          :placeholder="placeholder"
          class="input"
          placeholder-class="placeholder"
          @input="fieldInput"
          @blur="fiedBlur"
        />
        <input
          v-if="type === 'number'"
          :type="type"
          :value="inputVal"
          :placeholder="placeholder"
          class="input"
          placeholder-class="placeholder"
          @input="fieldInput"
          @blur="fiedBlur"
        />
        <input
          v-if="type === 'idcard'"
          :type="type"
          :value="inputVal"
          :placeholder="placeholder"
          class="input"
          placeholder-class="placeholder"
          @input="fieldInput"
          @blur="fiedBlur"
        />
        <!-- 包含 -->
        <view
          v-if="label.includes('身份证') || type === 'idcard'"
          class="upload-box"
        >
          <view class="upload-item" @click="uploadIdCard">
            <image
              class="img"
              :src="cardImg ? cardImg : imgDefault"
              mode="scaleToFill"
            />
            <u-loading class="loading" mode="circle" color="#5fc970" :show="showLoading"></u-loading>
          </view>
        </view>
      </view>
  </view>
</template>

export default {
  name: "PersonInput",
  props: {
    // 输入框类型
    type: {
      type: String,
      default: "text",
    },
    // 标题文本
    label: {
      type: String,
      default: "",
    },
    // 输入框提示
    placeholder: {
      type: String,
      default: "",
    },
    // 输入框的值
    inputVal: {
      type: String,
      default: "",
    },
    //验证码
    core: {
      type: String,
      default: "",
    },
    boxType:{
      type:[String,Number],
      default: "",
    },
    cardImg:{
      type:String,
      default: "",
    }
  },
  data() {
    return {
      locationImg: "XXXXXX/",
      url: fileUrl, // 上传图片地址
      file: null, //文件
      isUploadRe: false, //
      imgDefault: "/u001.png",//默认的展示图片
      showLoading:false,//是否展示加载动画
    };
  },
  methods: {
    fieldInput(e) {
      this.$emit("input", e.detail.value);
    },
    fiedBlur(e) {
      this.$emit("blur", e.detail.value);
    },
    // 图片上传成功回调主要是用于身份证这里
    uploadIdCard() {
      uni.chooseImage({
        count: 1,
        sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
        // sourceType: ['camera'], //从相册选择
        success: (chooseImageRes) => {
          this.showLoading = true;
          const tempFilePaths2 = chooseImageRes.tempFilePaths;
          uni.uploadFile({
            url: `XXXXXXX`,
            filePath: tempFilePaths2[0],
            formData: {
              parentKey: "miniApp",
              rentId: rentId,
            },
            name: "file",
            success: (uploadFileRes) => {
              this.showLoading = false;
              let res = JSON.parse(uploadFileRes.data);
              if(res.state){
                // 识别成功之后,调用回调函数
                // "type": "Front", "name": "姓名","id": "身份证号","addr": "地址","gender": "性别"
                let param = {
                  contact:res.result.name,
                  idCard:res.result.id,
                }
                this.$emit('recognize',param,this.boxType,tempFilePaths2[0])
              }else{
                this.showLoading = false;
                 uni.showToast({
                  title: `识别身份证号出错`,
                  duration: 2000,
                  icon: "none",
                });
              }
            },
            fail: (err) => {
              uni.showToast({
                  title: `${err}`,
                  duration: 2000,
                  icon: "none",
                });
            },
          });
        },
      });
    },
  },
};
  • 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
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
下单页面使用 order.vue
<template>
//用户模块,用户只有一份信息
  <view
    class="order-input"
    v-for="(item, index) in contacts"
    :key="index"
  >
    <PersonInput
      type="text"
      box-type="linkaddress"
      :cardImg="linkaddress.cardImg"
      :label="item.text"
      :inputVal="linkaddress[item.key]"
      v-model="linkaddress[item.key]"
      :placeholder="'请输入' + item.text"
      @recognize="recognize"
      @input="
        e => {
          fieldInput(e, item.key);
        }
      "
    ></PersonInput>
  </view>
  // 游客信息 可以填写多个游客信息,选择人数的
  <view
     class="order-input"
     v-for="(item, index) in formDate"
     :key="item.id"
   >
     <template
       v-for="(orderItem, itemIndex) in passenger"
     >
       <PersonInput
         type="text"
         :box-type="index"
         :cardImg="formDate[index].cardImg"
         :key="itemIndex"
         :label="orderItem.text"
         :inputVal="formDate[index][orderItem.key]"
         v-model="formDate[index][orderItem.key]"
         :placeholder="'请输入' + orderItem.text"
         @recognize="recognize"
         @input="
           e => {
             fieldInput(e, orderItem.key);
           }
         "
         @blur="
           e => {
             orderItem.key == 'idCard' ? fiedBlur(e, index) : '';
           }
         "
       ></PersonInput>
     </template>
     <view class="chooseaddress" @tap="chooseaddress(index)"
       >选择</view
     >
     <view class="delbox" @tap.stop="DelRoom(index)" v-if="value > 1">
       <text class="ddm-wc"></text>
     </view>
   </view>
</template>

data() {
  return {
  	// 用户表单
	linkaddress: {},
	//游客数据,多条
	formDate: [
        {
          id: Date.now(),
          userName: "",
          idCard: "",
          singleRoomNum: 0
        }
      ],
	}
}
// 手动选择联系人之后的数据回填
setNowItem(itemObj, index, cardImg) {
      if (index == "linkaddress") {
        let item = Object.assign(this.linkaddress, itemObj);
        this.contacts.forEach(obj => {
          if (Object.keys(item).includes(obj.key)) {
            this.$set(this.linkaddress, obj.key, item[obj.key]);
          }
          obj.key === "phoneNum" &&
            this.$set(this.linkaddress, obj.key, item.telno);
          obj.key === "personAddress" &&
            this.$set(this.linkaddress, obj.key, item.detailaddress);
        });
        this.$set(this.linkaddress, "cardImg", cardImg);
      } else {
        let nowIndex = parseInt(index);
        let item = Object.assign(this.formDate[nowIndex], itemObj);
        this.passenger.forEach(obj => {
          if (Object.keys(item).includes(obj.key)) {
            this.$set(this.formDate[nowIndex], obj.key, item[obj.key]);
          }
          obj.key === "phone" &&
            this.$set(this.formDate[nowIndex], obj.key, item.telno);
          obj.key === "userName" &&
            this.$set(this.formDate[nowIndex], obj.key, item.contact);
          obj.key === "personAddress" &&
            this.$set(this.formDate[nowIndex], obj.key, item.detailaddress);
        });
        this.$set(this.formDate[nowIndex], "cardImg", cardImg);
      }
    },
    /**
     * @description 身份证信息图片识别
     * @param {res} Object 身份证识别结果数据
     * */
    recognize(res, index, cardImg) {
      this.setNowItem(res, index, cardImg); //
    },
    /**
     * @description 用于处理新增客户信息时的动态添加对象
     * @param {type} 'fictitious'为虚拟实名信息,即生成得客户信息需要有数据
     * @param {index} 循环时的循环下标,用于处理一些循环事件
     */
    getPersonObj(type, index) {
      let newPersonObj = {};
      newPersonObj = this.passenger.reduce(
          (acc, cur) => {
            acc[cur.key] = "";
            return acc;
          },
          {}
        );
      newPersonObj = {
        ...newPersonObj,
        ...{ id: Date.now(), singleRoomNum: 0 }
      };
      return newPersonObj;
    },
    /**
     * @description 用于联系人过校验的方法
     *
     */
    validatePerson() {
      // 联系人过校验方法
      for (let i = 0; i < this.contacts.length; i++) {
        let item = this.contacts[i];
        if (
          this.linkaddress.hasOwnProperty(item.key) &&
          this.linkaddress[item.key] == ""
        ) {
          this.myShowToast(`请填写${item.text}`);
          return false;
        }
        if (item.key == "phoneNum") {
          if (
            this.linkaddress.hasOwnProperty("phoneNum") &&
            !this.myreg.test(this.linkaddress.phoneNum)
          ) {
            uni.showToast({
              title: "请输入正确的手机号码",
              icon: "none",
              duration: 2000
            });
            return false;
          }
        } else if (
          this.linkaddress.hasOwnProperty("idCard") &&
          !this.validateIdCard(this.linkaddress.idCard)
        ) {
          this.myShowToast(`请输入正确的身份证号`);
          return false;
        }
      }
      return true;
    },
    /**
     * @description 用于游客信息过校验的方法
     *
     */
    validateFormDate(index) {
      // 联系人过校验方法
      for (
        let i = 0;
        i < this.passenger.length;
        i++
      ) {
        let item = this.passenger[i];
        if (
          this.formDate[index].hasOwnProperty(item.key) &&
          this.formDate[index][item.key] == ""
        ) {
          this.myShowToast(`请填写游客${index + 1}${item.text}`);
          return false;
        }
        if (item.key == "phone") {
          if (
            this.formDate[index].hasOwnProperty("phone") &&
            !this.myreg.test(this.formDate[index].phone)
          ) {
            uni.showToast({
              title: `请正确填写游客${index + 1}手机号码`,
              icon: "none",
              duration: 2000
            });
            return false;
          }
        }
        if (item.key == "idCard") {
          if (
            this.formDate[index].hasOwnProperty("idCard") &&
            !this.validateIdCard(this.formDate[index].idCard)
          ) {
            this.myShowToast(`请正确填写游客${index + 1}身份证号`);
            return false;
          }
        }
      }
      return true;
    },
    // 提交表单时的校验
    submit(){
		// 校验联系人输入信息格式
          if (!this.validatePerson()) return false;
          for (let i = 0; i < this.formDate.length; i++) {
            if (!this.validateFormDate(i)) return 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
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226

呼~经过上面这些代码,包括初始化,包括选择联系人信息的回填,都要于后端配置的信息进行挂钩。提交表单的时候还需要对配置的表单内容进行校验。

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

闽ICP备14008679号