Vue+ElementUI实现表单动态渲染、校验(一)

Vue+ElementUI实现表单动态渲染、校验(一)

  • 项目需求
    • 1.vue表单实现递归渲染

项目需求

接到新的项目需求,需要把一个json文件动态渲染成表单,并添加各种校验规则等。经过各种查资料,最终完成了此功能开发,对这块的知识点进行梳理如下。

1.vue表单实现递归渲染

我们需要实现的Json文件格式如下:

// An highlighted block
 "configs": [
        {
            "name": "school1",
            "cnName": "学校一",
            "childNodes": [
                {
                    "name": "grade1",
                    "cnName": "一年级",
                    "props": [
                        {
                            "name": "class1",
                            "cnName": "一班",
                            "dataType": "int",
                            "desc": "班级人数",
                            "validator": {
                                "min": 20,
                                "max": 50,
                                "required": true
                            }
                        },
                        {
                            "name": "class2",
                            "cnName": "二班",
                            "dataType": "int",
                            "desc": "班级人数",
                            "validator": {
                                "min": 20,
                                "max": 50,
                                "required": true
                            }
                        },
                        {
                            "name": "class3",
                            "cnName": "三班",
                            "dataType": "int",
                            "desc": "班级人数",
                            "validator": {
                                "min": 20,
                                "max": 50,
                                "required": true
                            }
                        },
                    ]
                }
            ]
        },
        {
            "name": "school2",
            "cnName": "学校二",
            "childNodes": [
                {
                    "name": "grade1",
                    "cnName": "一年级",
                    "props": [
                        {
                            "name": "class1",
                            "cnName": "一班",
                            "dataType": "int",
                            "desc": "班级人数",
                            "validator": {
                                "min": 20,
                                "max": 50,
                                "required": true
                            }
                        }
                    ]
                },
                {
                    "name": "grade2",
                    "cnName": "二年级",
                    "props": [
                        {
                            "name": "class1",
                            "cnName": "一班",
                            "dataType": "int",
                            "desc": "班级人数",
                            "validator": {
                                "min": 20,
                                "max": 50,
                                "required": true
                            }
                        },
                        {
                            "name": "class2",
                            "cnName": "二班",
                            "dataType": "int",
                            "desc": "班级人数",
                            "validator": {
                                "min": 20,
                                "max": 50,
                                "required": true
                            }
                        },
                    ]
                }
            ]
        }
    ]

简单列举一下,由于我们需求的JSON可能会嵌套很多层,所以必须实现递归渲染。
index.vue
index.vue 本身可作为递归组件使用。 configs 为Json配置文件

<div class="form-group">
      <div v-for="(item, index) in configs" :key="index">
        <div class="titleMain">
          <span class="verticalLine"></span>{{ item.cnName }}
        </div>
        
        <!-- 判断json文件是否有childNodes,有的话,继续循环childNodes内的对象 -->
        
        <template v-if="item.childNodes">
          <div
            v-for="(itemChild, indexChild) in item.childNodes"
            :key="indexChild"
          >
          
           <!-- :configs="itemChild"  childNodes内部实现递归循环 -->
           
            <form-group
              v-if="itemChild.childNodes"
              :configs="itemChild"
            ></form-group>
             <!-- 展示动态表单组件 -->
              <div>
                <el-form
                  ref="formgroup"
                  class="dynamic-form"
                  :model="getModel(itemChild.props, 'form' + indexChild)"
                >
                  <dynamic-form
                    ref="dynamicForm"
                    v-for="(itemInput, indexInput) in itemChild.props"
                    :key="itemInput.name + index + indexInput"
                    :item="itemInput"
                    :childItem="itemChild"
                    :configs="configs"
                    :numberValidator="numberValidator"
                    :value="itemInput.value"
                    @input="handleInput($event, itemInput.name, itemInput)"
                  ></dynamic-form>
                </el-form>
              </div>
          </div>
        </template>
        <!-- 判断json文件是否有childNodes,没有的话,直接展示动态表单组件 -->
        <template v-else>
          <div>
            <div>
              <el-form
                ref="formgroup"
                class="dynamic-form"
                :model="getModel(itemChild.props, 'form2' + indexChild)"
              >
                <dynamic-form
                  ref="dynamicForm"
                  v-for="(itemInput, indexInput) in itemChild.props"
                  :key="itemInput.name + index + '_' + indexInput"
                  :item="itemInput"
                  :childItem="itemChild"
                  :configs="configs"
                  :numberValidator="numberValidator"
                  :value="itemInput.value"
                  @input="handleInput($event, itemInput.name, itemInput)"
                ></dynamic-form>
              </el-form>
            </div>
          </div>
        </template>
      </div>
    </div>

此处
Vue+ElementUI实现表单动态渲染、校验(一)_第1张图片文件的name名和组件名是一致的
在这里插入图片描述

dynamicForm.vue
项目中目前使用的组件都是输入框和下拉框,因此动态表单中只使用了el-input 和 el-select。此处逻辑是参照网上看到的帖子内容,并非完全自创。

 <el-form-item
    v-if="!item.hidden"
    :rules="rules"
    :label="item.cnName"
    :prop="item.name"
    class="formItem"
  >
    <el-input
      v-if="item.dataType === 'int'"
      v-bind="$attrs"
      v-on="$listeners"
      :placeholder="item.placeholder"
      @change="
        val => {
          item.valueChange
            ? item.valueChange(val, formData, clone, numberValidator)
            : valueChange()
        }
      "
      :disabled="item.disable"
      :readonly="item.readonly"
      :autosize="item.autosize"
      v-model="item.value"
    ></el-input>
    <el-input
      v-else-if="item.dataType === 'string'"
      v-bind="$attrs"
      v-on="$listeners"
      :placeholder="item.placeholder"
      :disabled="item.disable"
      :readonly="item.readonly"
      v-model="item.value"
    ></el-input>

    <el-select
      v-else-if="item.dataType === 'select'"
      v-bind="$attrs"
      v-on="$listeners"
      :multiple="item.multiple"
      :disabled="item.disabled"
      @change="
        val => {
          item.valueChange(val, childItem)
        }
      "
    >
      <el-option
        v-for="o in item.optionals"
        :key="o.value"
        :label="o.cnName"
        :value="o.value"
        :disabled="o.disabled"
      >
      </el-option>
    </el-select>
  </el-form-item>

json中props数组中的每一个对象对应了一个输入框,通过父子组件传参,将props中的对象遍历,分别传到dynamicForm组件,组件拿到props中每个对象的属性,对应展示即可。
Vue+ElementUI实现表单动态渲染、校验(一)_第2张图片
表单动态渲染的部分大概就是这样。

后面针对此json文件的校验部分进行梳理。

你可能感兴趣的:(前端,Vue,前端开发,javascript)