vue动态生成表单_vue element 表单验证

vue动态生成表单_vue element 表单验证前几天接了一个需求,需要动态生成一个表单数据,然后提交,提交完数据后。通过编辑按钮进入时,需要进行数据回填。没生成表单前的状态单机生成表单生成表单根据选择方式展示不同的表单元素如果从编辑页进入该页面有数据的话,进行数据回填样式同第三点相似,这里不再说明思路:请输入标题,请选择类型为父组件;请选择方式为子组件;根据请选择方式出来的内容为孙子组件难…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

前几天接了一个需求,需要动态生成一个表单数据,然后提交,提交完数据后。通过编辑按钮进入时,需要进行数据回填。

一、页面展示:


I. 没生成表单前的状态

Vue-UEedit
在这里插入图片描述
UEedit
在这里插入图片描述

II. 单机生成表单生成表单
在这里插入图片描述


III. 根据选择方式展示不同的表单元素

在这里插入图片描述


IV. 如果从编辑页进入该页面有数据的话,进行数据回填

样式同第三点相似,这里不再说明


二、思路:

请输入标题请选择类型 为父组件;请选择方式 为子组件;根据请选择方式出来的内容为孙子组件, 单选和下拉下面的生成参数是从孙组件


三、难点:

动态生成数据、数据多层传递(四层数据向下传递+四层数据向上传递)、数据格式转换、数据清空、
数据关联、数据解耦、空白表单数据添加、 含原始表单数据添加、表单数据删除、非响应式数据处理、
合并表单数据(判空+去重+重新排序)、深层数据传递监听


四、结构上分析:

(1)数据类型: 两层数据,三层数据,四层数据

二层数据:
新增
层级1 –> 层级2–>层级1(整合数据)–>提交
编辑
回填 层级1 –> 层级2
修改+新增 层级1 –> 层级2–>层级1 –> 提交

三层数据:
新增
层级1 –> 层级2–>层级3–>层级2–>层级1(整合数据)–>提交
编辑
回填 层级1 –> 层级2–>层级3
修改+新增 层级1 –> 层级2–>层级3–>层级2–>层级1(整合数据)–>提交

四层数据:
新增
层级1 –> 层级2–>层级3–>层级4–>层级3层级2–>层级1(整合数据)–>提交
编辑
回填 层级1 –> 层级2–>层级3–>层级4
修改+新增 层级1 –> 层级2–>层级3–>层级4–>层级3–>层级2–>层级1(整合数据)–>提交

(2)生成类型:

普通文本输入框、数字输入框、下拉框、

关联值类型1:文本输入框+文本输入框、

关联值类型2:文本输入框+单选框

(3)关键值传递: 新增/编辑来回数据格式化转换:

例如:

提交时候分享参数:

// 格式化URL动态添加数据格式
    formatURL(obj) { 
   
      let url = "";
      const tempArr = [];
      const arr = Object.keys(obj);
      let leng = 0;
      arr.map(item => { 
   
        if (item.slice(-1) * 1 > leng) { 
   
          leng = item.slice(-1) * 1;
        }
      });
      for (let i = 1; i <= leng; i += 1) { 
   
        const obj1key = arr.filter(item => item.slice(-1) * 1 === i);
        const obj1 = { 
   };
        obj1key.map(item => { 
   
          obj1[item] = obj[item];
        });
        tempArr.push(obj1);
      }
      tempArr.forEach(v => { 
   
        Object.keys(v).map(key => { 
   
          url += `${ 
     key}=${ 
     v[key]}&`;
        });
      });
      url = url.substring(0, url.length - 1);
      return `${ 
     this.data.link}?${ 
     url}`;
    }

Jetbrains全家桶1年46,售后保障稳定

回填时解析分享参数:


  // 解析返回的分享参数
    formatDEcodeURL(URL) { 
   
      const urlsrc = URL;
      const arr1 = [];
      const arr2 = [];
      const obj = { 
   };
      urlsrc.split("&").map(v => { 
   
        if (v.substring(0, 4) === "link") { 
   
          arr1.push(v);
        }
        if (v.substring(0, 4) === "type") { 
   
          arr2.push(v);
        }
      });
      arr1.forEach(v => { 
   
        arr2.forEach(k => { 
   
          if (v.charAt(4) === k.charAt(4)) { 
   
            obj[`link${ 
     v.charAt(4)}`] = v.substring(6);
            obj[`type${ 
     k.charAt(4)}`] =
              k.substring(6) === "1" ? "必填" : "非必填";
          } else { 
   
            obj[`link${ 
     v.charAt(4)}`] = v.substring(6);
            obj[`type${ 
     k.charAt(4)}`] =
              k.substring(6) === "1" ? "必填" : "非必填";
          }
        });
      });
      this.todoObj = obj;
      const max = Math.max(arr1.length, arr2.length);
      for (let i = 0; i < max; i += 1) { 
   
        this.addShareLink();
      }
    },

(4)监听第二三层数据变化,实现数据实时改变:

例如:

  watch: { 
   
    // 新增页面 监测父组件传入值变化
    secdown: { 
   
      handler(val) { 
   
        this.changeChoose(val);
      },
      deep: true,
      immediate: true
    },
    // 编辑页面 监测子组件变化,来刷新子组件其余值
    chooseTypes: { 
   
      handler(val) { 
   
        this.changeTypes(val);
      },
      deep: true,
      immediate: true
    }
  },

五、代码分析:

动态生成数据父组件讲解

HTML

           <div
              v-for="item in createFormArray"
              :key="item.id">
              <el-row
                :gutter="24"
                style="margin-top:10px;">
                <el-col :span="3">
                  <div class="item-title">输入项{ 
   { 
    item.id }}:</div>
                </el-col>
                <el-col :span="3">
                  <el-input
                    v-model="createFormObj[item.value]"
                    placeholder="请输入标题"/>
                </el-col>
                <el-col :span="3">
                  <el-select
                    v-model="createFormObj[item.kind]"
                    placeholder="请选择类型">
                    <el-option
                      v-for="(item,index) in choose"
                      :key="index"
                      :label="item.label"
                      :value="item.value"/>
                  </el-select>
                </el-col>
                
                <!-- 嵌入的第二层,请选择方式组件-->
                
                <DynamicData
                  :dynamical = "item.id"
                  :secdown = "item.indexDA"
                  @receive= "receive"/>
              </el-row>
            </div>

JS

import DynamicData from "./dynamic_data"; //引入选择方式组件
export default { 
   
components: { 
   
    VueEditor,
    DynamicData
  },
data() { 
   
    return { 
   
          createIndex:1,      //生成表单的索引
          countPage: 0,       //输入需要生成表单的个数
          createFormObj: { 
   },     //存放每一个生成表单对象
          createFormArray: [],   //生成表单所有生成对象的数组
          choose: [         //请选择类型选择器里面的选择值
		      { 
   
		          value: 1,
		          label: "必填"
		        },
		        { 
   
		          value: 2,
		          label: "非必填"
		        }
			],
          
          
    }
    },
    createForm() { 
   
      for (; this.createIndex <= this.countPage; this.createIndex += 1) { 
   
      
       //造数据,给每一项添加上 id,value,kind, type方便我们后面绑定数据使用(绑定的数据我们给后面加上索引区分)
       
        this.createFormArray.push({ 
       
          id: this.createIndex,
          value: `link${ 
     this.createIndex}`,
          kind: `kind${ 
     this.createIndex}`,
          type: `type${ 
     this.createIndex}`
        });
      }
    }
}


DynamicData儿子组件讲解

HTML层

<template>
  <div class="data-manage-container">
    <el-col :span="3">
      <el-select
        v-model="chooseTypes"
        placeholder="请选择方式"
        @change="storeType">
        <el-option
          v-for="item in options"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
    </el-col>
    <div>
      <!-- 传入 项数 和 选择的方式 -->
      <InputItem
        :child = "secdown"
        :showitem = "dynamical"        //从儿子组件将“选择的方式” 传给孙子组件
        :showindex="+chooseTypes" //从儿子组件将“项数” 传给孙子组件
        @lastchild="getChild"/>         //为了获取孙子组件数据,绑定函数传递过去
    </div>
  </div>
</template>

JS层

<script>
import InputItem from "./show_input_item";  //引入孙子组件

export default { 
   
  name: "DynamicData",
  components: { 
   
    InputItem
  },
  props: { 
   
    dynamical: { 
   
      type: Number,
      default: 0
    },
    types: { 
   
      type: Function,
      default() { 
   }
    },
    secdown: { 
   
      type: Object,
      default: () => ({ 
   })
    }
  },
  data() { 
   
    return { 
   
      chooseTypes: "", 
      options: [     //选择的类型
        { 
   
          value: 1,
          label: "文字输入"
        },
        { 
   
          value: 2,
          label: "电话号码"
        },
        { 
   
          value: 3,
          label: "文件上传"
        },
        { 
   
          value: 4,
          label: "下拉框选择"
        },
        { 
   
          value: 5,
          label: "单选框"
        },
        { 
   
          value: 6,
          label: "数字输入"
        },
        { 
   
          value: 7,
          label: "Hidden"
        }
      ],
      childrenMess: []
    };
  },
  watch: { 
   
    secdown: { 
   
      handler(val) { 
   
        this.changeChoose(val);
      },
      deep: true,
      immediate: true
    }
  },
  methods: { 
   
    getChild(val) { 
       // 接受孙子组件传递过来的数据,并将数据传给父组件
      this.$emit("receive", { 
    ...this.childrenMess, ...val });
    },
    storeType(val) { 
        // 每天选择时,接受孙子组件传递过来的数据,并将数据传给父组件
      this.childrenMess = { 
    id: this.dynamical, value: val };
      this.$emit("receive", { 
    ...this.childrenMess });
    },
    changeChoose(val) { 
   
      this.chooseTypes = val.type;
    }
  }
};
</script>

InputItem孙子组件讲解

HTM层:

<template>
  <div class="data-manage-container">
    <div v-show="showindex === 1">
      <el-col :span="3">
        <el-input
          v-model="generated_data.input_title"
          placeholder="请输入默认值"
          @change="getTextOne(showindex,$event)"/>
      </el-col>
      <el-col :span="3">
        最大长度:<el-input-number
          v-model="generated_data.numLength"
          :min="1"
          size="small"
          label="描述文字"
          @change="getNumberOne(showindex,$event)"/>
      </el-col>
    </div>

    <div v-show="showindex === 4 || showindex === 5">
      <div style="visibility:hidden;">
        <el-select
          v-model="generated_data.formvalue"
          placeholder="请输入默认值">
          <el-option
            v-for="item in selectValue"
            :key="item.value"
            :label="item.label"
            :value="item.value"/>
        </el-select>
      </div>
      <div class="reduceparams">
        <el-row
          :gutter="10"
          style="padding-left:200px;">
          <el-col :span="5">
            <div
              class="item-title"
              @click = "formAddParam"> <i class="el-icon-circle-plus"/></div>
          </el-col>
        </el-row>
        <el-row
          v-for="(todo,index) in FormTodoParams"
          :key="todo.id">
          <el-row
            :gutter="20"
            style="padding-left:200px;padding-top:10px;">
            <el-col :span="1">
              <div
                class="item-title"
                style="padding-top:10px;"
                @click = "formRemoveParam(index)"> <i class="el-icon-remove"/></div>
            </el-col>
            <el-col
              :span="1"
              style="margin-top:10px;">
              参数:
            </el-col>
            <el-col
              :span="3"
              style="margin-left: -38px;">
              <el-input
                v-model.trim="formObj[todo.value]"
                placeholder="输入内容"
                size="mini"
                clearable
                @change="getParamsFour(showindex,formObj)"/>
            </el-col>
            <el-col
              :span="3"
              style="margin-left: 10px;
              margin-top:10px;">
              <el-radio-group
                v-model="generated_data.defaltRadio"
                size="small"
                @change="getSelectFour(showindex,$event)">
                <el-radio
                  :label="formObj[todo.value]">选择为默认值</el-radio>
              </el-radio-group>
            </el-col>
          </el-row>
        </el-row>
      </div>
    </div>

    <div v-show="showindex === 6">
      <el-col :span="3">
        <el-input
          v-model="generated_data.selectData"
          placeholder="请输入默认值"
          @change="getTextSix(showindex,$event)"/>
      </el-col>
      <el-col :span="3">
        最小值:<el-input-number
          v-model="generated_data.selectData_min"
          :min="0"
          size="small"
          label="最小值"
          @change="getMinSix(showindex,$event)"/>
      </el-col>
      <el-col :span="3">
        最大值:<el-input-number
          v-model="generated_data.selectData_max"
          :min="0"
          size="small"
          label="最大值"
          @change="getMaxSix(showindex,$event)"/>
      </el-col>
    </div>
    <div v-show="showindex === 7">
      <el-col :span="3">
        <el-input
          v-model="generated_data.selectnomalData"
          placeholder="请输入默认值"
          @change="getMaxSeven(showindex,$event)"/>
      </el-col>
    </div>
  </div>
</template>

HTML这里主要是根据不同的选择方式显示不同的表单内容,


JS层

<script>
export default { 
   
  name: "InputItem",
  components: { 
   },
  props: { 
   
    showindex: { 
   
      type: Number,
      default: 0
    },
    showitem: { 
   
      type: Number,
      default: 0
    },
    child: { 
   
      type: Object,
      default: () => ({ 
   })
    }
  },
  data() { 
   
    return { 
   
      indexNormal: 0,
      formObj: { 
   },
      selectValue: [
        { 
   
          value: 1,
          label: "必填"
        },
        { 
   
          value: 0,
          label: "非必填"
        }
      ],
      generaData: { 
   
        inputTitle: "",
        numLength: 0,
        formvalue: "",
        selectData: 0,
        selectData_min: 0,
        selectData_max: 0,
        selectnomalData: "",
        defaltRadio: "",
        value: 0
      },
      formIndex: 0,
      FormTodoParams: [],
      typeFour: { 
   
        choose: "",
        chooseObj: { 
   }
      },
      typeFive: { 
   
        choose: "",
        chooseObj: { 
   }
      }
    };
  },
  watch: { 
   
    // 新增页面 监测父组件传入值变化
    child: { 
   
      handler(val) { 
   
        this.watchChoose(val);
      },
      deep: true,
      immediate: true
    },
    // 编辑页面 监测子组件变化,来刷新子组件其余值
    generaData: { 
   
      handler(val) { 
   
        this.watchGeneraData(val);
      },
      deep: true,
      immediate: true
    }
  },
  mounted() { 
   },
  methods: { 
   
    // 编辑时有数据触发 数据回填
    watchChoose(val) { 
   
      this.generaData.inputTitle = val.text;
      this.generaData.numLength = val.length;
      this.generaData.selectData = +val.num_default;
      this.generaData.selectData_min = +val.min;
      this.generaData.selectData_max = +val.max;
      this.generaData.formvalue = val.is_required;
      this.generaData.selectnomalData = val.novel;
      this.generaData.defaltRadio = val.default;
      this.generaData.id = val.id;
      this.generaData.type = this.showindex;

      if (val.type_value && val.type_value.length) { 
   
        this.indexNormal = val.type_value.length;
        val.type_value.forEach((v, i) => { 
   
          this.FormTodoParams.push({ 
   
            id: i + 1,
            value: `value${ 
     i + 1}`
          });
        });
        for (let i = 1; i <= val.type_value.length; i += 1) { 
   
          this.formObj[`value${ 
     i}`] = val.type_value[i - 1];
        }
      }
    },
    watchGeneraData(val) { 
   
      return val;
    },
    // 没有 子组件时刷新页面
    getInputBox(index) { 
   
      if (index === 1 || index === 6 || index === 7) { 
   
        this.watchGeneraData(this.generaData);
        this.integrationData(index);
      }
    },
    // 当选择"单选"或者"下拉"时生成表单元素
    formAddParam() { 
   
      this.formIndex += 1;
      if (this.indexNormal > 0) { 
   
        this.FormTodoParams.push({ 
   
          id: this.formIndex + this.indexNormal,
          value: `value${ 
     this.formIndex + this.indexNormal}`
        });
      } else { 
   
        this.FormTodoParams.push({ 
   
          id: this.formIndex,
          value: `value${ 
     this.formIndex}`
        });
      }
    },
    formRemoveParam(index) { 
   
      this.FormTodoParams.splice(index, 1);
    },
    // 整合并获取输入数据
    integrationData(index) { 
   
      switch (index) { 
   
        case 1:
          this.$emit("lastchild", { 
   
            ...this.generaData,
            type: this.showindex,
            id: this.showitem
          });
          break;
        case 4:
          this.$emit("lastchild", { 
   
            ...this.generaData,
            ...this.typeFour,
            type: this.showindex,
            id: this.showitem
          });
          break;
        case 5:
          this.$emit("lastchild", { 
   
            ...this.generaData,
            ...this.typeFive,
            type: this.showindex,
            id: this.showitem
          });
          break;
        case 6:
          this.$emit("lastchild", { 
   
            ...this.generaData,
            type: this.showindex,
            id: this.showitem
          });
          break;
        case 7:
          this.$emit("lastchild", { 
   
            ...this.generaData,
            type: this.showindex,
            id: this.showitem
          });
          break;
        default:
          break;
      }
    },
    // 下拉框处理
    getSelectFour(index, val) { 
   
      if (index === 4) { 
   
        this.typeFour.choose = val;
        this.integrationData(index);
      } else { 
   
        this.typeFive.choose = val;
        this.integrationData(index);
      }
    },
    // 下拉框处理
    getParamsFour(index, val) { 
   
      if (index === 4) { 
   
        this.typeFour.chooseObj = val;
        this.integrationData(index);
      } else { 
   
        this.typeFive.chooseObj = val;
        this.integrationData(index);
      }
    }
  }
};
</script>

这里代码并不是全部代码,只是抽出部分进行讲解,父组件有1300行左右的代码,主要是细节处理所有并没有贴出来。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/234118.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • MySQL 修改字段类型或长度

    MySQL 修改字段类型或长度mysql>altertable表名modifycolumn字段名类型;例如数据库中address表city字段是varchar(30)修改类型可以用(谨慎修改类型,可能会导致原有数据出错)mysql> altertableaddressmodifycolumncitychar(30);修改长度可以用(修改长度,要保证不短与已有数据,以保证原有数

  • 联合索引在B+Tree上的存储结构及数据查找方式[通俗易懂]

    联合索引在B+Tree上的存储结构及数据查找方式[通俗易懂]最困难的事情就是认识自己!个人网站,欢迎访问!前言:本篇文章主要是阐述下联合索引在B+Tree上的实际存储结构。本文主要讲解的内容有:联合索引在B+树上的存储结构联合索引的查找方式为什么会有最左前缀匹配原则在分享这篇文章之前,我在网上查了关于MySQL联合索引在B+树上的存储结构这个问题,翻阅了很多博客和技术文章,其中有几篇讲述的与事实相悖。具体如下:很多博客中都是说:联合索引在B+树上的非叶子节点中只会存储联合索引中的第一个索引字段的.

  • 什么是Boot Loader

    什么是Boot Loader

  • Maven–如何下载JSONObject相关依赖架包

    Maven–如何下载JSONObject相关依赖架包一、开发场景Java开发当中经常需要Json格式的数据,这就用到JSONObject类,本文章只提供以下两种JSONObject对应架包的下载方式。com.alibaba.fastjson.JSONObject(依赖1个架包fastjson-1.2.28.jar)net.sf.json.JSONObject(依赖6个架包commons-beanutils-1.9.3.jar、commons-c…

  • Qtum量子链新官网全面升级,正式上线!

    Qtum量子链新官网全面升级,正式上线!

  • 15道常考SpringBoot面试题整理

    15道常考SpringBoot面试题整理1、什么是SpringBoot?多年来,随着新功能的增加,spring变得越来越复杂。只需访问https://spring.io/projects页面,我们就会看到可以在我们的应用程序中使用的所有Spring项目的不同功能。如果必须启动一个新的Spring项目,我们必须添加构建路径或添加Maven依赖关系,配置应用程序服务器,添加spring配置。因此,开始一个新的spring项目需…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号