这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战
动态表单需求及实现思路
我的项目有一个通用的 form 组件,内部渲染了海量的 form 元素,有input、checkbox、select,radio 等等。
这个 form 组件,在不同的页面要根据需求展示不同的表单元素。
这样一个复杂的组件,我肯定不能手动排版啊。
于是果断跟后台商量一下,通过后台返回的 json 数据来动态渲染页面的表单元素,另外一些不方便返回的数据,本地写个 json。
比如这种:
[{
type: input,
value: '',
default: 0,
describle: '请输入年龄',
size: 'middle'
},
{
type: select,
value: '',
default: '北京',
describle: '请选择城市',
size: 'middle',
options: ['北京','天津']
},
...
]
然后我们遍历这个 json 数据,根据 type 字段渲染出表单元素就行了。
写完美滋滋。
一个问题
一提交数据,发现后端验证不通过。
打开 network,看看何方妖孽在兴风作浪?
结果发现因为项目用的是 vue,由于所有的表单数据都会定义在 data 函数的 form属性下,比如
data(){
return {
form: {
username: '',
userRole: '',
ifLoginForbid: false,
....
}
}
}
导致在使用 axios 提交数据时把所有的表单的数据一起提交了,这里的 form 是几个页面共有的所有的数据。
因为页面通过各种 v-for 来动态的生成了当前页面需要的表单元素,但 data 中定义的数据在提交的时候不好进行判断。
如果手动去写各种 if 条件判断来提交哪些数据,过滤哪些数据,判断太多,代码笨重还不好维护。
怎么解决
所以就想到使用 form 自带的 submit,嘿嘿嘿嘿。
因为 form 自带的 submit 是根据页面存在的元素来提交数据的,如果我们使用这个 submit 方法,先把后台需要的数据动态的采集出来,那不就相当于给 data 中定义的 form 加了一层过滤吗?
所以能够完美的解决我的需求。
那么,问题是在 vue 中如何使用 form 的 submit 来获取数据呢?
首先,我们有一个 form 表单,表单所有的元素都有 name 属性。
<form action="####" @submit.prevent="submitform" ref="form">
<el-input type="text" v-model="username" name="username">
<el-select v-model="userRole" placeholder="请选择" name=""userRole>
<el-option
v-for="item in userRoleList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-checkbox v-model="ifLoginForbid" name="ifLoginForbid">禁止登录?</el-checkbox>
<input type="submit" value="" v-show="false" @click="submitform">
</form>
然后,通过手动调用 this.submitform() 来获取 form 表单中的数据
...
methods: {
submitform(){
// 通过 FormData 取得相应的 form 上的数据
const formData = new FormData(this.$refs['form'])
const data = {}
// entries返回一个 iterator对象 ,此对象可以遍历访问FormData中的键值对
for (let [key, val] of formData.entries()) {
console.log([key, val] )
Object.assign(data, { [key]: val })
}
return data // {username: ''username'', userRole: 1}
}
}
疑?? 我的 ifLoginForbid 去了哪里~~打印下看看
console.log(formData.getKey('ifLoginForbid'))
// null
是个 null值,这就离谱了。
查看下元素,发现 checkbox 是未选中的状态,那是不是应为没选中的原因导致 formData 根本没有拿到这个数据呢?
那我勾选这个 checkbox 后再测试一波
console.log(formData.getKey('ifLoginForbid'))
// ''
汰!这不科学啊,居然是个空字符!checkbox 绑定的不应该是个 boolean 类型的值吗?
再次查看元素,看看是哪个刁民又在害我。
发现选中状态的 el-checkbox 里的 input 是这样:
<input type="checkbox" aria-hidden="false" class="el-checkbox__original" value="">
这是组件变异太深了吗? 没有探入的去研究。但我知道正常的 input 大概是这样:
<input type="checkbox" :checked="checked" :name="name" @change="change" :value="checked"/>
所以依照上面的规则,我自己实现了一个 myCheckbox 组件:
<template>
<input type="checkbox"
:name="name"
:checked="checked"
:value="checked"
@change="change" />
</template>
<script>
export default {
props: {
checked: {
type: Boolean
},
name: {
type: String
}
},
model: {
prop: 'checked',
event: 'change'
},
methods: {
change(e) {
this.$emit('change', e.target.checked)
}
}
}
</script>
在父组件里使用:
<component :is="'myCheckbox'" v-model="checked" :name="'ifLoginForbid'" />
再次查看formData.getKey('ifLoginForbid') // true
成功了,这次我们成功的获取到了页面所有的表单元素的数据,生成了要提交给后台的 data。
nice~~