版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_24147051/article/details/84104056
前几天接了一个需求,需要动态生成一个表单数据,然后提交,提交完数据后。通过编辑按钮进入时,需要进行数据回填。
- 没生成表单前的状态
- 单机生成表单生成表单
- 根据选择方式展示不同的表单元素
- 如果从编辑页进入该页面有数据的话,进行数据回填
样式同第三点相似,这里不再说明
思路:
请输入标题,请选择类型 为父组件;请选择方式 为子组件;根据请选择方式出来的内容为孙子组件
难点:
动态生成数据,数据多层传递(三层数据向下传递+三层数据向上传递),数据格式转换,数据清空
第一步:
动态生成数据父组件讲解
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孙子组件讲解
HTML
<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 {
formObj: {},
chooseState: "",
selectValue: [
{
value: 1,
label: "必填"
},
{
value: 2,
label: "非必填"
}
],
generated_data: {
input_title: "",
numLength: 0,
formvalue: "",
selectData: "",
selectData_min: "",
selectData_max: "",
selectnomalData: "",
defaltRadio: ""
},
formIndex: 0,
FormTodoParams: [],
typeOne: {
text: "",
length: 0
},
typeFour: {
choose: "",
chooseObj: 0
},
typeFive: {
choose: "",
chooseObj: 0
},
typeSix: {
text: "",
number1: 0,
number2: 0
},
typeSeven: {
text: ""
}
};
},
watch: { //使用孙子组件监听儿子组件的数据变化,进行相应处理
child: {
handler(val) {
this.watchChoose(val);
},
deep: true,
immediate: true
}
},
mounted() {},
methods: {
watchChoose(val) { //孙子组件进行数据回填
this.generated_data.input_title = val.default;
this.generated_data.numLength = val.max_length;
this.generated_data.selectData = val.default;
this.generated_data.selectData_min = val.min;
this.generated_data.selectData_max = val.max;
this.generated_data.selectnomalData = val.default;
this.generated_data.defaltRadio = val.default;
if (val.type_value && val.type_value.length > 0) {
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];
}
}
// formObj[todo.id]
},
formAddParam() { //当选择方式为4或者5时,需要有添加按钮,单机生成输入框
this.formIndex += 1;
this.FormTodoParams.push({
id: this.formIndex,
value: `value${this.formIndex}`
});
},
formRemoveParam(index) { // 删除生成 ,当选择方式为4或者5时 添加的输入框
this.FormTodoParams.splice(index, 1);
},
// 整合并获取输入数据 将不同情况的数据从孙子组件传递给儿子组件
integrationData(index) {
switch (index) {
case 1:
this.$emit("lastchild", this.typeOne);
break;
case 4:
this.$emit("lastchild", this.typeFour);
break;
case 5:
this.$emit("lastchild", this.typeFive);
break;
case 6:
this.$emit("lastchild", this.typeSix);
break;
case 7:
this.$emit("lastchild", this.typeSeven);
break;
default:
break;
}
},
getTextOne(index, val) { //选择方式为1
this.typeOne.text = val;
this.integrationData(index);
},
getNumberOne(index, val) { //选择方式为1
this.typeOne.length = val;
this.integrationData(index);
},
getSelectFour(index, val) { //选择方式为4
if (index === 4) {
this.typeFour.choose = val;
this.integrationData(index);
} else {
this.typeFive.choose = val;
this.integrationData(index);
}
},
getParamsFour(index, val) { //选择方式为4或者5
if (index === 4) {
this.typeFour.chooseObj = val;
this.integrationData(index);
} else {
this.typeFive.chooseObj = val;
this.integrationData(index);
}
},
getTextSix(index, val) { //选择方式为6
this.typeSix.text = val;
this.integrationData(index);
},
getMinSix(index, val) { //选择方式为6
this.typeSix.number1 = val;
this.integrationData(index);
},
getMaxSix(index, val) { //选择方式为6
this.typeSix.number2 = val;
this.integrationData(index);
},
getMaxSeven(index, val) { //选择方式为7
this.typeSeven.text = val;
this.integrationData(index);
}
}
};
</script>
这里代码并不是全部代码,只是抽出部分进行讲解,父组件有1300行左右的代码,主要是细节处理所有并没有贴出来。