前言

在此记录下使用 elementuiantDesignantDesignVue 的表格嵌套表单校验的一些经验。

要达到的目的是:有个多行表格,每一行有多个表单项(比如输入框),表单项填完值后,点击提交,校验表格中所有表单项,校验通过则将整个表格数据送到后台。还可以重新给表格赋值(比如进入详情页面)。效果如下:

正文

elementuielementPlus 使用方式一样,这里就只用 elementui 来举例,版本是 2.x

antDesignVue 1.x 版本有两种表单校验方式,v-decoratorFormModel ,要达到上面的效果需要用 FormModel 的方式,而后面 2.x 及以后的版本将两种方式合并,统一用 FormModel 的方式。

antDesign 我这里用的 3.x 版本,用的是 getFieldDecorator 方式,并且是函数式组件的写法。

需要注意的是如果使用的是 react@<15.3.0,则 getFieldDecorator 调用不能位于纯函数组件中。

elementui 用法

只需要将 prop 里面的属性和v-model表单数据引用保持一致即可,例如:

:prop="'rows.'+scope.$index+'.age'"
v-model.trim="asdfform.rows[scope.$index].age"

页面结构

<el-form :model="asdfform" ref="asdfform" label-width="20px">
<el-table :data="asdfform.rows">
<el-table-column prop="name" label="name"></el-table-column>
<el-table-column prop="age" label="age">
<template slot-scope="scope">
<el-form-item label=" " :rules="[{required: true, message:'请输入'}]" :prop="'rows.'+scope.$index+'.age'">
<el-input v-model.trim="asdfform.rows[scope.$index].age"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="address" label="address">
<template slot-scope="scope">
<el-form-item label=" " :rules="[{required:true,message:'请输入'}]" :prop="'rows.'+ scope.$index + '.address'">
<el-input v-model.trim="asdfform.rows[scope.$index].address"></el-input>
</el-form-item>
</template>
</el-table-column>
</el-table>
</el-form>
<el-button type="primary" size="small" @click="handleSubmit">表单提交</el-button>
<el-button type="danger" size="small" @click="resetTableData">重新给表格赋值</el-button>

数据和方法定义

data() {
return {
asdfform: {
rows: [
{ key: 1, name: `Edrward ${1}`, age: "1234", address: "1234" },
{ key: 2, name: `Edrward ${2}`, age: "1234", address: "1234" },
{ key: 3, name: `Edrward ${3}`, age: "", address: "" },
],
},
};
},
methods: {
handleSubmit() {
this.$refs.asdfform.validate((valid) => {
console.log('表格数据',JSON.parse(JSON.stringify(this.asdfform)));
if (valid) {
}
});
},
resetTableData() {
this.asdfform.rows = [
{ key: 1, name: `Edrward ${1}`, age: "1234", address: "1234" },
{ key: 2, name: `Edrward ${2}`, age: "1234", address: "1234" },
{ key: 3, name: `Edrward ${3}`, age: "", address: "" },
{ key: 4, name: `Edrward ${4}`, age: "4", address: "44" },
];
},
},

完整示例

antDesignVue 1.x 用法

如果用的是FormModel 方式,那么写法和 elementui 中一样,不过需要先引入

import { FormModel } from 'ant-design-vue'
Vue.use(FormModel)

页面中使用

<a-form-model :model="asdfform" ref="asdfform">
<a-table
:columns="asdfcolumns"
:dataSource="asdfform.rows"
bordered
:rowKey="(record,index)=>index"
>
<template slot="age" slot-scope="text,record, index">
<a-form-model-item
label=" "
:prop="'rows.'+index+'.age'"
:rules=" [{required: true, message:'请输入'}]"
>
<a-input v-model="asdfform.rows[index].age" />
</a-form-model-item>
</template>
<template slot="address" slot-scope="text,record,index">
<a-form-model-item
label=" "
:prop="'rows.'+index+'.address'"
:rules="[{required: true, message:'请输入' }]"
>
<a-input v-model="asdfform.rows[index].address" />
</a-form-model-item>
</template>
</a-table>
<a-form-item>
<a-button type="primary" @click="handleSubmit">Submit</a-button>
</a-form-item>
</a-form-model>
data: function () {
return {
asdfform: {
rows: [
{ key: 1, name: `Edrward ${1}`, age: '1234', address: '1234' },
{ key: 2, name: `Edrward ${2}`, age: '1234', address: '1234' },
{ key: 3, name: `Edrward ${3}`, age: '', address: '' },
]
},
asdfcolumns: [
{ title: 'name', dataIndex: 'name', width: '25%' },
{
title: 'age',
dataIndex: 'age',
width: '15% ',
scopedSlots: { customRender: 'age' }
},
{
title: 'address',
dataIndex: 'address',
width: '40%',
scopedSlots: { customRender: 'address' }
},
{ title: 'operation', dataIndex: 'operation' },
],
}
},
methods: {
handleSubmit() {
this.$refs.asdfform.validate(valid => {
console.log(this.asdfform)
if (valid) { }
});
}
}

antDesign 3.x 用法

react 中没有 v-model 的用法,这里通过 setState + useEffect 来实现。

vue 中使用 asdfform 定义表单数据,asdfform.rows 定义表格数据,也就是表格数据是嵌套在表单数据里面的,所以表单项改变,表格数据也会同步改变。

react 中表格数据和表单数据的分开维护的,所以当表格数据改变时,需要在 useEffect 里面同步表单数据,同样表单数据变化后,提交函数中也会创建一份新的表格数据。

1、定义基本结构

这里使用了 Form.create 和 getFieldDecorator 的方式校验表单。

经 Form.create() 包装过的组件会自带 this.props.form 属性。

使用 Form.create 处理后的表单具有自动收集数据并校验的功能,但如果您不需要这个功能,或者默认的行为无法满足业务需求,可以选择不使用 Form.create 并自行处理数据。

const App = ({ form }) => {

    const { getFieldDecorator, setFieldsValue, validateFields } = form;

    // 定义表格数据
const [data, setData] = useState([
{ key: 1, name: `Edrward ${1}`, age: "1234", address: "1234" },
{ key: 2, name: `Edrward ${2}`, age: "1234", address: "1234" },
{ key: 3, name: `Edrward ${3}`, age: "", address: "" },
]); return (
<>
<Form>
<Table
columns={asdfcolumns}
dataSource={data}
pagination={false}
rowKey="key"
></Table>
<Form.Item>
<Button type="primary" onClick={handleSubmit}>
Submit
</Button>
<Button onClick={handleReset}>reset</Button>
</Form.Item>
</Form>
</>
);
} const WrappedMyFormComponent = Form.create()(App);
export default WrappedMyFormComponent;

2、添加表格列,根据需要自定义列内容

const asdfcolumns = [
{ title: "name", dataIndex: "name", width: "25%" },
{
title: "age",
dataIndex: "age",
width: "15%",
render: (text, record, index) => (
<Form.Item>
{getFieldDecorator(`data.${index}.age`, {
rules: [{ required: true, message: "请输入" }],
initialValue: record["age"],
})(<Input />)}
</Form.Item>
),
},
{
title: "address",
dataIndex: "address",
width: "40%",
render: (text, record, index) => (
<Form.Item>
{getFieldDecorator(`data.${index}.address`, {
rules: [
{
required: true,
message: "请输入!",
},
],
initialValue: record["address"],
})(<Input />)}
</Form.Item>
),
},
{ title: "operation", dataIndex: "operation" },
];

3、添加提交函数和重置数据函数(给表格重新赋值)

const handleSubmit = () => {
validateFields((err, values) => {
console.log("Received values of form: ", values);
if (!err) {
const updatedData = data.map((item, index) => ({
...item,
age: values.data[index].age,
address: values.data[index].address,
}));
console.log(updatedData); //更新后的数据
}
});
};
const handleReset = () => {
let newData = [
{ key: 1, name: `Edrward ${1}`, age: "1", address: "2" },
{ key: 2, name: `Edrward ${2}`, age: "3", address: "4" },
{ key: 3, name: `Edrward_${3}`, age: "", address: "" },
{ key: 4, name: `Edrward ${3}`, age: "5", address: "6" },
setData(newData),
];
};

4、表格数据改变后同步更新表单

useEffect(() => {
//当 data 状态更新时,手动设置表单字段的值
const fields = data.reduce((acc, record, index) => {
acc[`data.${index}.age`] = record.age;
acc[`data.${index}.address`] = record.address;
return acc;
}, {});
setFieldsValue(fields);
}, [data]);

antDesign 的完整代码

import { Button, Form, Input, Table } from "antd";
import { useEffect, useState } from "react";
const App = ({ form }) => {
const { getFieldDecorator, setFieldsValue, validateFields } =
form;
const asdfcolumns = [
{ title: "name", dataIndex: "name", width: "25%" },
{
title: "age",
dataIndex: "age",
width: "15%",
render: (text, record, index) => (
<Form.Item>
{getFieldDecorator(`data.${index}.age`, {
rules: [{ required: true, message: "请输入" }],
initialValue: record["age"],
})(<Input />)}
</Form.Item>
),
},
{
title: "address",
dataIndex: "address",
width: "40%",
render: (text, record, index) => (
<Form.Item>
{getFieldDecorator(`data.${index}.address`, {
rules: [
{
required: true,
message: "请输入!",
},
],
initialValue: record["address"],
})(<Input />)}
</Form.Item>
),
},
{ title: "operation", dataIndex: "operation" },
];
const [data, setData] = useState([
{ key: 1, name: `Edrward ${1}`, age: "1234", address: "1234" },
{ key: 2, name: `Edrward ${2}`, age: "1234", address: "1234" },
{ key: 3, name: `Edrward ${3}`, age: "", address: "" },
]);
const handleSubmit = () => {
validateFields((err, values) => {
if (!err) {
console.log("Received values of form: ", values);
const updatedData = data.map((item, index) => ({
...item,
age: values.data[index].age,
address: values.data[index].address,
}));
console.log(updatedData);
}
});
}; const handleReset = () => {
let newData = [
{ key: 1, name: `Edrward ${1}`, age: "1", address: "2" },
{ key: 2, name: `Edrward ${2}`, age: "3", address: "4" },
{ key: 3, name: `Edrward_${3}`, age: "", address: "" },
{ key: 4, name: `Edrward ${3}`, age: "5", address: "6" },
setData(newData),
];
}; useEffect(() => {
//当 data 状态更新时,手动设置表单字段的值
const fields = data.reduce((acc, record, index) => {
acc[`data.${index}.age`] = record.age;
acc[`data.${index}.address`] = record.address;
return acc;
}, {});
setFieldsValue(fields);
}, [data]);
return (
<>
<Form>
<Table
columns={asdfcolumns}
dataSource={data}
pagination={false}
rowKey="key"
></Table>
<Form.Item>
<Button type="primary" onClick={handleSubmit}>
Submit
</Button>
<Button onClick={handleReset}>reset</Button>
</Form.Item>
</Form>
</>
);
};
const WrappedMyFormComponent = Form.create()(App);
export default WrappedMyFormComponent;

在elementui,antDesign,antDesignVue中表格嵌套多个表单项校验的更多相关文章

  1. jeecg中vaildfrom的复杂的表单校验

    简介 jeecg生成的页面都是使用validfrom组件来确保数据的完整性和准确性. 凡要验证格式的元素均需绑定datatype属性,datatype可选值内置有10类,用来指定不同的验证格式. 如果 ...

  2. 应用二:Vue之ElementUI Form表单校验

    (注:本文适用于有一定Vue基础或开发经验的读者,文章就知识点的讲解不一定全面,但却是开发过程中很实用的)   表单校验是前端开发过程中最常用到的功能之一,根据个人的工作经验总结在此对表单校验功能的基 ...

  3. element-ui中的表格嵌套表格

    element-ui中有详细的各种表格及表格方法.也有表格展开出现二级的样式,但是却没有表格嵌套二级表格的方案,于是就自己写了一个,样式图如下: 展开后如下 这就是一个普通的二级表格嵌套,用的是el- ...

  4. elementUI表单嵌套表格并对每行进行校验

    elementUI表单嵌套表格并对每行进行校验 elementUI 表单嵌套表格并进行校验. 目录 效果展示 代码链接 关键代码 完整代码 效果展示 先看看这是不是需要的效果^_^ ​ 如图,Elem ...

  5. ExtJS中实现嵌套表格

    先看效果: 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:/ ...

  6. 【JS中循环嵌套常见的六大经典例题+六大图形题,你知道哪几个?】

    首先,了解一下循环嵌套的特点:外层循环转一次,内层循环转一圈. 在上一篇随笔中详细介绍了JS中的分支结构和循环结构,我们来简单的回顾一下For循环结构: 1.for循环有三个表达式,分别为: ①定义循 ...

  7. Vue2.0+ElementUI+PageHelper实现的表格分页

    Vue2.0+ElementUI+PageHelper实现的表格分页 前言 最近做了一些前端的项目,要对表格进行一些分页显示.表格分页的方法有很多,从宏观上来说分为物理分页和逻辑分页,由于逻辑分页(即 ...

  8. 认识HTML中表格、列表标签以及表单控件

    前端之HTML,CSS(二) HTML标签 列表标签 无序列表:闭标签,由<ul><li></li>...</ul>组合而成,效果成纵向列表.格式:&l ...

  9. CSS控制表格嵌套

    网页设计应用中,当我们不能完全放弃表格的使用时,为了达到预期的效果,不免要用到表格嵌套(特别是多层嵌套)方式来进行布局.可能很多同仁都遇到过这样的问题,为了达到显示效果要为每一个(每一层)的表格写不同 ...

  10. HTML表格嵌套、合并表格

    一.表格元素< table> table常用属性 border:边框像素 width,height:表格宽度/高度 bordercolor:表格边框颜色 bgcolor:表格背景颜色 二. ...

随机推荐

  1. elementui|dropdown|下拉菜单作为模态框使用

    elementui|dropdown|下拉菜单作为模态框使用 背景 场景:下拉菜单作为模态框使用: 操作:下拉菜单设置触发条件点击展示/隐藏:trigger="click" 目的: ...

  2. Solana编译失败探讨(OpenEuler RISC-V版)

      Solana 是 2017 年由 Anatoly Yakovenko 创立的开源项目,旨在打造高性能.去中心化且低成本的区块链平台2.它采用独特的 Proof of History(PoH)共识机 ...

  3. 学习Kotlin语法(四)

    简介 在上一节,我们对Kotlin中函数的相关知识有了大致的了解,本章节我们将去了解一些Kotlin中的作用域函数. 目录 let:处理可空对象,链式操作 run:对象配置 + 计算返回值 with: ...

  4. 从零开始:在Qt中使用OpenGL绘制指南

    本文只介绍基本的 QOpenGLWidget 和 QOpenGLFunctions 的使用,想要学习 OpenGL 的朋友,建议访问经典 OpenGL 学习网站:LearnOpenGL CN 本篇文章 ...

  5. SMU Autumn 2024 Trial 1

    A. Load Balancing 很明显题意要的就是让我们把每个数往平均值靠,这样就保证最大值-最小值最小 但是当sum%n !=0的时候就说明无法每个数都等于sum/n,所以处理的方法就是,先计算 ...

  6. Redis底层数据结构 链表

    链表 Redis 的 List 对象的底层实现之一就是链表.C 语言本身没有链表这个数据结构的,所以 Redis 自己设计了一个链表数据结构. 链表节点结构设计 先来看看「链表节点」结构的样子: ty ...

  7. eolinker校验规则之 Json结构定位:返回结果校验的方法和案例(父参、子参内容校验)

    如下图,订单编号的参数在data父字段内 Eolinker返参校验的写法就需要有些变化 先写Data父参,添加子字段,再写子参 预期结果不支持全局变量 可通过添加绑定,绑定前一个接口返回参数,进行匹配

  8. 如何使用Streamlit快速创建仪表盘?

    上文有快速带大家了解streamlit,因为工作需要,这两天尝试构建了仪表盘,也就是咱们常说的Dashboard,本篇文章将教你如何使用 Streamlit 快速创建一个简单的仪表盘. 前言 Stre ...

  9. Tortoise-ORM级联查询与预加载性能优化

    title: Tortoise-ORM级联查询与预加载性能优化 date: 2025/04/26 12:25:42 updated: 2025/04/26 12:25:42 author: cmdra ...

  10. bootstrap4下拉菜单无法显示问题

    刚才在菜鸟教程学习bootstrap4时在按钮组章节中遇到了下拉菜单,可是自己没有调试出来!!! 我把菜鸟的代码copy(全部)到本地发先可以运行!!! 找了半天原因,可能是自己导入的js文件有错!! ...