背景: 主要是官网给的只有一个Input框的示例,不满足需求,这里就不赘述了~
ant-design 1.7.8版本中,Form组件的内置属性被设计为操作数据的主要方式
需求:外层是可以动态添加,删除的,里层也是可以动态添加,删除的,每层都包含多个属性--
如图所示:
我们把方案分为:
外层的-添加,删除;
内层的-添加,删除;
1. 数据仍然是通过v-decorator双向绑定的,v-decorator绑定的外层只拼接了index, 里层拼接了index后又拼接了里层循环的childIndex,来保证唯一的,原因还是由于ant-design的老版本中,form表单的格式是键值对形式,拼接后打印出来如下图所示;
即便是v-for循环的,但不是数组对象的形式,而是Object平铺的形式,如果不通过index,childIndex去拼接,键重名的话就报错了。
{
eventName-0: '变量1',
eventId-0: '变量id1',
eventName-1: '变量2',
eventId-1: '变量id2',
dataneeder-0-0: '接收方1',
dataneeder-0-1: '接收方2',
dataneeder-1-0: '接收方3',
dataneeder-1-1: '接收方4',
}
实现方案如下图所示:
接上一张图继续..
2. data里数据定义如下图所示:
3. 外层的添加
4. 外层的删除
跟单层嵌套循环的区别是,多层嵌套在删除后,不仅要把没被删除的父节点的数据赋值,还要把没被删除的子元素的数据赋值,形成新的Object类型键值对的数据,再通过form的setFieldsValue重新赋值给form。
5. 里层的子节点的添加
6. 里层的子节点的删除
这里面都有注释,删除子节点,主要通过取出老的form的值后,通过判断Object的键,这个字符串里有几个短杠 '-',有1个表示是外层的数据,有2个表示是里层的数据,数据格式参照下图:
{
eventName-0: '变量1',
eventId-0: '变量id1',
eventName-1: '变量2',
eventId-1: '变量id2',
dataneeder-0-0: '接收方1',
dataneeder-0-1: '接收方2',
dataneeder-1-0: '接收方3',
dataneeder-1-1: '接收方4',
}
(1)判断一个短杠,是外层的数据,不需要动,就把这些数据直接赋值
(2)判断是2个短杠,要判断前面第一个短杠后面的数字跟父节点的Index比较, 如果相等,表示操作的是这个父节点下的数据,处理下index, 把新的处理后的键,赋值。
(3)判断是2个短杠,但跟父节点的index不相等,说明不是操作的这个父元素下的子节点,也不需要动,直接赋值。
(4)把处理后的newFieldsValue重新赋值给form
delChildNode(parentIndex, childIndex) {
if (this.keysList[parentIndex].childKeysList.length === 1) {
this.$message.warning('至少保留一个属性')
return
}
// 删除数组中的数据
this.keysList[parentIndex].childKeysList.splice(childIndex, 1)
// 取出表单中的数据
const oldFieldsValue = this.form.getFieldsValue()
const newFieldsValue = {}
// 1. 赋值外层的数据
for(const objKey in oldFieldsValue) {
// 把oldFieldsValue里面,对象名为一个'-'的直接赋值到newFieldsValue
if (objKey.match(/-/g)?.length === 1) {
// 说明是第一层数据,直接赋值
newFieldsValue[objKey] = oldFieldsValue[objKey]
} else {
// 把oldFieldsValue里面,第一个'-'后面的数字取出来
// 取出来的数字如果等于parentIndex, 说明操作的是这个里面的数据,要处理下index
if (objKey.match(/-(\d+)/) && parseInt(objKey.match(/-(\d+)/)[1]) === parentIndex) {
for (let j = 0; j < this.keysList[parentIndex].childKeysList.length; j++) {
let oldIndex = j
if (j >= childIndex) {
oldIndex = j + 1
}
// 重新设置表单值
for (const key in this.childModelType) {
newFieldsValue[this.childModelType[key] + parentIndex + '-' + j] = oldFieldsValue[this.childModelType[key] + parentIndex + '-' + oldIndex]
}
}
} else {
// 没被操作的直接赋值
newFieldsValue[objKey] = oldFieldsValue[objKey]
}
}
}
this.form.setFieldsValue(newFieldsValue)
},
7. 提交时,也会带校验,这里就是官方的写法了。
handleSubmit(e) {
e.preventDefault()
this.form.validateFields((err, values) => {
if (err) return
console.log('submit Values', values)
})
},
写到最后,我自己觉得里层子节点的删除逻辑有点绕的,如果有其它可以简化代码的思路,欢迎交流评论,一起学习共成长~