当前位置 : 主页 > 网络编程 > JavaScript >

vue动态生成新表单并且添加验证校验规则方式

来源:互联网 收集:自由互联 发布时间:2023-02-08
目录 一、需求场景以及注意事项 需求场景 注意事项 二、代码结构 template中 data中 methods中的按钮事件,也就是触发渲染之前的事件 三、ant-design中的校验规则 a-form-model a-form-model-item 四
目录
  • 一、需求场景以及注意事项
    • 需求场景
    • 注意事项
  • 二、代码结构
    • template中
    • data中
    • methods中的按钮事件,也就是触发渲染之前的事件
  • 三、ant-design中的校验规则
    • a-form-model
    • a-form-model-item
  • 四、在点击对话框确定按钮时获取该表单对象,并得出打印结果
    • 五、遇到的问题及优化
      • 数据提交前校验
      • 优化一:element-ui同样适用
      • 循环生成表单数据重复,在点击时生成,多次点击就会多次生成,在生成前添加判断即可

    一、需求场景以及注意事项

    需求场景

    1.用户输入数值,点击按钮弹出对话框的同时,按照用户输入的数值进行表单的渲染。

    2.点击按钮之后,渲染效果如下:

    注意事项

    首先声明我这里使用的是ant-design,现在只要在网上一搜都是vue+element的动态生成以及数据绑定,所以就打算出一篇文章记录一下。

    下面先说与UI框架无关的注意事项,无论使用的是Element还是ant都要关注的点,在文末会说有关于ant生成表单的校验规则。

    以下几点是重点内容,建议细品。

    • 1.在初始情况下,每一个表单项(比如说每一个input)的绑定数据都为空,也就是在data中无定义,但是整个表单的数据绑定为空数组。这个空数组就相当于表单项数据绑定的载体。
    • 2.在渲染表单,也就是渲染DOM元素之前,必须填充这个空数组,使数组中的值与表单项需要绑定的值一一对应。除此之外,只要是在动态生成的内容中中,需要绑定的数据,都需要在渲染之前动态生成完毕。
    • 3.在渲染表单之前,必须使用v-if判断数组是否为空,为空则不渲染。
    • 4.此处v-if不得使用v-show代替,因为v-show代表的是页面元素存在,处于隐藏状态。但是我们需要绑定的数据还没生成好,最终会报一堆undefined。而v-if的本质是操作DOM,控制其是否渲染,而v-show是操作样式,控制其显示隐藏。

    二、代码结构

    template中

    此处会体现注意点三和四

    1.我这里使用的Number函数是ant提供的,作用就是将用户输入的数值由字符串转换成Number类型,注意转换成Number类型是必须进行的,如果是字符串,遍历出来的也只是字符串中的具体字符。

    转换成Number之后效果也就类似于:

    for(let i = 0; i < arr.length; i++)
    <!-- 监测构建信息对话框 -->
    <a-modal
        :title="monitorTitle"
        :visible="monitorModalVisible"
        @ok="monitorModalOk"
        @cancel="monitorModalCancel"
        okText="确定"
        cancelText="取消"
        :width=850>
        <!-- 当控制展开折叠的数组有值时再渲染:注意点三/四 -->
        <div v-if="monitorExpand.length > 0">
            <!-- 通过数值一循环生成监测区 -->
            <div  v-for="(item1,index1) in Number(addForm.add_monitor_number)" :key="index1">
                <!-- 监测区标题与展开折叠文字 -->
                <div class="monitor">
                    <span class="monitor_title">监测区-{{item1}}</span>
                    <!-- 控制监测区折叠与展开的文字与图标 -->
                    <div>
                        <span v-show="monitorExpand[index1].expanded" @click="monitorFormExpand(index1)" style="color:#4257B9;cursor: pointer;">
                            <a-icon type="up"/>
                            <span>折叠</span>
                        </span>
                        <span v-show="!monitorExpand[index1].expanded" @click="monitorFormExpand(index1)" style="color:#4257B9;cursor: pointer;">
                            <a-icon type="down"/>
                            <span>展开</span>
                        </span>
                    </div>
                </div>
                <!-- 监测区表单,需要展开折叠的效果,所以需要变量来控制 -->
                <div class="monitor_form" v-show="monitorExpand[index1].expanded">
                    <a-form-model ref="monitorFormRef" :model="monitorForm" :label-col="{span:6}" :wrapper-col="{ span: 17 }">
                        <a-row>
                            <a-col :span="12">
                                <a-form-model-item label="名称:" :rules="{ required: true, message: '名称不能为空', trigger: 'blur'}" :prop="'monitor_area.'+index1+'.monitor_name'">
                                    <a-input v-model="monitorForm.monitor_area[index1].monitor_name" placeholder="请输入监测构建信息" :disabled="modalDisabled"/>
                                </a-form-model-item>
                            </a-col>
                            <a-col :span="12">
                                <a-form-model-item label="位置:" :rules="{ required: true, message: '位置不能为空', trigger: 'blur'}" :prop="'monitor_area.'+index1+'.monitor_position'">
                                    <a-input v-model="monitorForm.monitor_area[index1].monitor_position" placeholder="请输入监测构建信息" :disabled="modalDisabled"/>
                                </a-form-model-item>
                            </a-col>
                        </a-row>
                        <a-form-model-item label="监测点数值:" :label-col="{span:3}" :wrapper-col="{ span:21 }">
                            <!-- 通过数值二循环生成监测点数 -->
                            <a-col :span="4" v-for="(item2,index2) in Number(addForm.add_point_number)" :key="index2">
                                <a-form-model-item :style="{ marginRight:'5px'}" :rules="{ required: true, message: '数值不能为空', trigger: 'blur'}" :prop="'monitor_area.'+index1+'.points.'+index2">
                                    <a-input v-model="monitorForm.monitor_area[index1].points[index2]" :placeholder="index2+1" :disabled="modalDisabled"/>
                                </a-form-model-item>
                            </a-col>
                        </a-form-model-item>
                    </a-form-model>
                </div>
            </div>
        </div>
    </a-modal>
    

    data中

    此处会体现注意点一

    methods中的按钮事件,也就是触发渲染之前的事件

    1.事件绑定

    2.事件处理函数

    此处体现注意点三:页面DOM元素渲染之前必须生成该DOM元素需要绑定的相关数据。

    此处的折叠展开也是相关数据,也需要渲染之前生成好。

    此处我的绑定数据是通过按钮生成的,大家也可以根据自己的实际需求,以其他事件为介质。

    // 按钮点击事件
    inputPointMessage(){
        // 在添加时,只有输入了测区数量以及监测点数,才能进行构建信息的填写
        if(this.addTitle=='添加'){
            if(this.addForm.add_monitor_number == ''){
                return this.$message.warning('请先输入测区数量')
            }
            if(this.addForm.add_point_number == '')
                return this.$message.warning('请先输入监测点数')
        }
        // 生成控制折叠展开的数组和表单绑定对象,使用let声明,避免出现意外的全局变量
        for(let i = 0; i < this.addForm.add_monitor_number ;i++){
            // 生成控制折叠展开的数组
            this.monitorExpand.push({expanded:true});
            // 生成表单绑定对象
            this.monitorForm.monitor_area.push({
                // 名称
                monitor_name :'',
                // 位置
                monitor_position :'',
                // 保存监测点数的数组
                points :[]
            })
        }
        // 打开对话框
        this.monitorModalVisible = true
    },
    

    3.控制展开与折叠的事件处理函数

    // 信息表单的展开折叠
    monitorFormExpand(index){
        this.monitorExpand[index].expanded = !this.monitorExpand[index].expanded
    },

    三、ant-design中的校验规则

    a-form-model

    1.在此标签上不进行rules属性的绑定,但是需要绑定model属性 。

    a-form-model-item

    1.在此标签上必须绑定prop属性,外带一张ant官网截图说明。由于我们需要使用校验规则,所以该属性的绑定是必须的。

    2.在此标签上必须绑定rules属性,用于定义校验规则。

    3.如果还看不懂可看官网有关于FormModel组件的最后一个演示示例。我就是根据这个将需求写出来的。

    四、在点击对话框确定按钮时获取该表单对象,并得出打印结果

    五、遇到的问题及优化

    数据提交前校验

    通过我之前的方式生成的表单是多个,那么vue实例中,一个monitorFormRef就对应了多个,如下:

    那么这个数组的每一项都会有一个validate方法,只能循环调用validate方法了:

    // 监测构建信息对话框确定按钮
    monitorModalOk(){
         // 在点击对话框确定的时候,对表单进行校验
         console.log(this.$refs.monitorFormRef)
         // 创建空数组,保存多个校验结果
         let valids = []
         this.$refs.monitorFormRef.forEach((item)=>{
             item.validate(valid => {
                 // 将校验结果保存到数组中,当前item对应表单的校验全部通过为true,否则为false
                 valids.push(valid)
             });
         });
         console.log(valids,'valids')
         // 遍历校验结果数组,只要一个为false,则返回false,否则返回true
         let finalValid = valids.every((item)=>{
             return item == true
         });
         console.log(finalValid,'finalValid')
         // 当全部表单的表单项没有全部通过,直接返回
         if(!finalValid) return
         // 执行拿到数据之后的业务代码,业务代码不进行演示
         // 关闭当前对话框
         this.monitorModalVisible = false
     },
    

    优化一:element-ui同样适用

    只有用户输入了前面提到的数值一和数值二(只能是正整数,不包含零),再继续向下进行,以及表单的渲染,之前是只拿了字符串非空进行校验,之前的代码已经注释掉,目前修改如下:

    数值一和数值二的校验规则一样,只体现其一:

    //  测区数量
     add_monitor_number: [{required: true, message: '测区数量不能为空', trigger: 'blur' },
             {type:'number',message:'仅支持输入正整数(不包含0)', trigger: 'blur',transform(value){ 
             if(value){
                 // 将输入的值转为数字
                 var val = Number(value)
                 if(/^[+]{0,1}(\d+)$/.test(val) && val != 0) return val
                 // 返回false即为校验失败
                 return false
             }
     }} ],
    
     // 按钮点击事件
    // 按钮点击事件
    inputPointMessage(){
          // 定义变量判断用户输入了相应的值才可以进行表单的渲染,都通过校验时为true,否则为false
          let tempValid = true;
          // 对数值一和数值二两个值的正确性进行校验(只能是正整数,不包含零),只有两个值的校验通过了才可以继续对表单进行渲染
          this.$refs.addFormRef.validateField(['add_monitor_number','add_point_number'],(error)=>{
              // 当error存在即校验未全部通过,
              if (error) tempValid = false;
          })
          console.log(tempValid)
          // 校验不通过直接返回
          if(!tempValid) return;
          // if(this.addTitle=='添加'){
          //     if(this.addForm.add_monitor_number == ''){
          //         return this.$message.warning('请先输入测区数量')
          //     }
          //     if(this.addForm.add_point_number == ''){
          //         return this.$message.warning('请先输入监测点数')
          //     }
          // }
          // 生成控制折叠展开的数组和表单绑定对象,使用let声明,避免出现意外的全局变量
          for(let i = 0; i < this.addForm.add_monitor_number ;i++){
              // 生成控制折叠展开的数组
              this.monitorExpand.push({expanded:true});
              // 生成表单绑定对象
              this.monitorForm.monitor_area.push({
                  // 名称
                  monitor_name :'',
                  // 位置
                  monitor_position :'',
                  // 保存监测点数的数组
                  points :[]
              })
          }
          // 打开对话框
          this.monitorModalVisible = true
      },
    

    循环生成表单数据重复,在点击时生成,多次点击就会多次生成,在生成前添加判断即可

    当前表单绑定的数据有值时,不再生成表单绑定数据。

    // 当前表单没有绑定数据时,生成表单对象
    if(this.monitorForm.monitor_area.length == 0){
        // 生成控制折叠展开的数组和表单绑定对象,使用let声明,避免出现意外的全局变量
        for(let i = 0; i < this.addForm.add_monitor_number ;i++){
            // 生成控制折叠展开的数组
            this.monitorExpand.push({expanded:true});
            // 生成表单绑定对象
            this.monitorForm.monitor_area.push({
                // 名称
                actual_measure_region_name :'',
                // 位置
                actual_measure_region_position :'',
                // 保存监测点数的数组
                actual_measure_region_value :[]
            })
        }
    }
    

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持易盾网络。

    网友评论