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)
blank

相关推荐

  • QUOTENAME函数的用法

    QUOTENAME函数的用法quotename函数的语法为:quotename('expression1','expression2')expression1:指的是需要被特殊处理的字符expre

  • 数据库复习笔记(全覆盖,包括往年部分真题)

    ##1、数据库系统概述**1.1数据库的基本概念**数据库:长期储存在计算机内、有组织的、可共享的大量数据的集合。*基本特征:*数据按一定的数据模型组织、描述和储存可为各种用户共享、冗余度较小、易扩展数据独立性较高数据:描述事物的符号记录数据有结构的:记录是计算机存储数据的一种格式或一种方法数据库管理系统及其功能:位于…

  • 浓缩就是精华「建议收藏」

    浓缩就是精华「建议收藏」 『凡人牧场』人生启示录:被称为世上最经典的25句话(转载)   作者:晶晶鱼 提交日期:2003-12-3115:32:40    1,记住该记住的,忘记该忘记的。改变能改变的,接受不能改变的。      2,能冲刷一切的除了眼泪,就是时间,以时间来推移感情,时间越长,冲突越淡,仿佛不断稀释的茶。      3,怨言是上天得至人类最大的供物,也是人

  • mac 安装配置android sdk[通俗易懂]

    mac 安装配置android sdk[通俗易懂]一、安装sdk在mac上可以使用brew包管理工具来安装软件,所以要安装sdk,首先需要安装brew包,详情可参照我上一篇博客,这里就不过多赘述。1、安装好brew后,通过以下命令进行sdk的安装brewinstallandroid-sdk2、查看是否已安装成功,在终端执行:android二、配置sdk1、查看sdk安装路径brewlistandroid-sdk可见,我的sdk的安装路径是在/opt/homebrew/Caskroom/android.

  • python分割字符串输出_python字符串分割「建议收藏」

    python分割字符串输出_python字符串分割「建议收藏」内置split()函数str.split(sep=None,maxsplit=-1)sep为自定义分割符,maxsplit为最大分割次数,默认值-1进行全部分割注意以下区别:str.split()以空格分割,包括连续空格str.split(”)同样以空格分割,但是不能识别连续空格,会返回两空格之间的空字符串python3docre模块的split()函数re.split(patte…

  • ASP.NET虚拟主机配置方案

    ASP.NET虚拟主机配置方案系统盘C:当然是最重要的。一:c盘给Administrator和System权限,完全控制二:c\DocumentsandSettings,c:\Inetpub给Administrator和S

发表回复

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

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