add form submit example
This commit is contained in:
21
packages/dooringx-doc/src/docs/4.4.md
Normal file
21
packages/dooringx-doc/src/docs/4.4.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
title: 表单验证提交思路
|
||||||
|
sTitle: 常见问题
|
||||||
|
order: 20
|
||||||
|
---
|
||||||
|
|
||||||
|
表单验证提交有非常多的做法,因为数据全部是联通的,或者直接写个表单组件也可以。
|
||||||
|
|
||||||
|
在不使用表单组件时,简单的做法是为每个输入组件做个验证函数与提交函数。
|
||||||
|
|
||||||
|
这样是否验证就取决于用户的选取,而抛出的输入可以让用户选择放到哪,并由用户去命名变量。
|
||||||
|
|
||||||
|
在点击提交按钮时,调用所有组件的验证函数与提交函数,使其抛给上下文,再通过上下文聚合函数聚合成对象,最后可以通过发送函数发送给对应后端,从而完成整个流程。你可以在example中试下这个demo。
|
||||||
|
|
||||||
|
如果操作人员能看懂后端提供的接口文档,那么就可以让操作人员自己通过命名来拼出后端想要的字段。
|
||||||
|
|
||||||
|
如果不需要文档,那么某些值也可以在开发时写死。
|
||||||
|
|
||||||
|
另外的做法是可以专门写个提交按钮,固定了参数,以及部分规则,比如规定在页面中的所有表单都会被收集提交。
|
||||||
|
|
||||||
|
那么我们可以利用数据源,将所有表单输出内容自动提交给数据源,最后的提交按钮按数据源规定格式的key提取,发送给后端。
|
@@ -2,7 +2,7 @@
|
|||||||
* @Author: yehuozhili
|
* @Author: yehuozhili
|
||||||
* @Date: 2021-08-03 10:45:06
|
* @Date: 2021-08-03 10:45:06
|
||||||
* @LastEditors: yehuozhili
|
* @LastEditors: yehuozhili
|
||||||
* @LastEditTime: 2021-08-03 10:45:07
|
* @LastEditTime: 2021-08-05 14:35:49
|
||||||
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\formComponents\switch.tsx
|
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\formComponents\switch.tsx
|
||||||
*/
|
*/
|
||||||
import React, { useMemo, memo } from 'react';
|
import React, { useMemo, memo } from 'react';
|
||||||
@@ -25,10 +25,10 @@ const MSwitch = (props: MSwitchProps) => {
|
|||||||
const store = props.config.getStore();
|
const store = props.config.getStore();
|
||||||
return (
|
return (
|
||||||
<Row style={{ padding: '10px 20px' }}>
|
<Row style={{ padding: '10px 20px' }}>
|
||||||
<Col span={6} style={{ lineHeight: '30px' }}>
|
<Col span={8} style={{ lineHeight: '30px' }}>
|
||||||
{(option as any)?.label || '文字'}:
|
{(option as any)?.label || '文字'}:
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={18}>
|
<Col span={16}>
|
||||||
<Switch
|
<Switch
|
||||||
checked={props.current.props[(option as any).receive] || ''}
|
checked={props.current.props[(option as any).receive] || ''}
|
||||||
onChange={(checked) => {
|
onChange={(checked) => {
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
* @Author: yehuozhili
|
* @Author: yehuozhili
|
||||||
* @Date: 2021-07-07 14:31:20
|
* @Date: 2021-07-07 14:31:20
|
||||||
* @LastEditors: yehuozhili
|
* @LastEditors: yehuozhili
|
||||||
* @LastEditTime: 2021-08-03 10:45:52
|
* @LastEditTime: 2021-08-05 15:10:23
|
||||||
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\formTypes.ts
|
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\formTypes.ts
|
||||||
*/
|
*/
|
||||||
export interface FormBaseType {
|
export interface FormBaseType {
|
||||||
@@ -10,14 +10,12 @@ export interface FormBaseType {
|
|||||||
}
|
}
|
||||||
export interface FormInputType extends FormBaseType {
|
export interface FormInputType extends FormBaseType {
|
||||||
label: string;
|
label: string;
|
||||||
text: string;
|
|
||||||
}
|
}
|
||||||
export interface FormActionButtonType {}
|
export interface FormActionButtonType {}
|
||||||
export interface FormAnimateControlType {}
|
export interface FormAnimateControlType {}
|
||||||
|
|
||||||
export interface FormSwitchType extends FormBaseType {
|
export interface FormSwitchType extends FormBaseType {
|
||||||
label: string;
|
label: string;
|
||||||
value: boolean;
|
|
||||||
}
|
}
|
||||||
export interface FormMap {
|
export interface FormMap {
|
||||||
input: FormInputType;
|
input: FormInputType;
|
||||||
|
@@ -2,9 +2,41 @@
|
|||||||
* @Author: yehuozhili
|
* @Author: yehuozhili
|
||||||
* @Date: 2021-07-07 14:22:51
|
* @Date: 2021-07-07 14:22:51
|
||||||
* @LastEditors: yehuozhili
|
* @LastEditors: yehuozhili
|
||||||
* @LastEditTime: 2021-07-09 13:52:51
|
* @LastEditTime: 2021-08-05 14:53:12
|
||||||
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\functionMap\index.ts
|
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\functionMap\index.ts
|
||||||
*/
|
*/
|
||||||
import { FunctionCenterType } from 'dooringx-lib/dist/core/functionCenter';
|
import { FunctionCenterType } from 'dooringx-lib/dist/core/functionCenter';
|
||||||
|
|
||||||
export const functionMap: FunctionCenterType = {};
|
export const functionMap: FunctionCenterType = {
|
||||||
|
上下文转对象: {
|
||||||
|
fn: (ctx, next, _config, args) => {
|
||||||
|
const arr = args['_sk'];
|
||||||
|
const key = args['_r'];
|
||||||
|
const param: Record<string, any> = {};
|
||||||
|
arr.forEach((v: string) => {
|
||||||
|
param[v] = ctx[v];
|
||||||
|
});
|
||||||
|
ctx[key] = param;
|
||||||
|
console.log(ctx);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
config: [
|
||||||
|
{
|
||||||
|
name: '输入要获取的上下文',
|
||||||
|
data: ['ctx'],
|
||||||
|
options: {
|
||||||
|
receive: '_sk',
|
||||||
|
multi: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '输入要生成的上下文',
|
||||||
|
data: ['ctx'],
|
||||||
|
options: {
|
||||||
|
receive: '_r',
|
||||||
|
multi: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
* @Author: yehuozhili
|
* @Author: yehuozhili
|
||||||
* @Date: 2021-02-27 21:33:36
|
* @Date: 2021-02-27 21:33:36
|
||||||
* @LastEditors: yehuozhili
|
* @LastEditors: yehuozhili
|
||||||
* @LastEditTime: 2021-08-03 23:21:01
|
* @LastEditTime: 2021-08-05 10:54:22
|
||||||
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\index.tsx
|
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\index.tsx
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@ import { ContainerOutlined, HighlightOutlined } from '@ant-design/icons';
|
|||||||
import commandModules from './commanderModules';
|
import commandModules from './commanderModules';
|
||||||
import { functionMap } from './functionMap';
|
import { functionMap } from './functionMap';
|
||||||
import { Formmodules } from './formComponentModules';
|
import { Formmodules } from './formComponentModules';
|
||||||
|
import InputCo from './registComponents/inputCo';
|
||||||
|
|
||||||
const LeftRegistMap: LeftRegistComponentMapItem[] = [
|
const LeftRegistMap: LeftRegistComponentMapItem[] = [
|
||||||
{
|
{
|
||||||
@@ -21,6 +22,12 @@ const LeftRegistMap: LeftRegistComponentMapItem[] = [
|
|||||||
displayName: '按钮',
|
displayName: '按钮',
|
||||||
urlFn: () => import('./registComponents/button'),
|
urlFn: () => import('./registComponents/button'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'basic',
|
||||||
|
component: 'input',
|
||||||
|
img: 'icon-anniu',
|
||||||
|
displayName: '输入框',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const defaultConfig: Partial<InitConfig> = {
|
export const defaultConfig: Partial<InitConfig> = {
|
||||||
@@ -38,7 +45,9 @@ export const defaultConfig: Partial<InitConfig> = {
|
|||||||
customRender: <div>我是自定义渲染</div>,
|
customRender: <div>我是自定义渲染</div>,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
initComponentCache: {},
|
initComponentCache: {
|
||||||
|
input: { component: InputCo },
|
||||||
|
},
|
||||||
rightRenderListCategory: [
|
rightRenderListCategory: [
|
||||||
{
|
{
|
||||||
type: 'style',
|
type: 'style',
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
* @Author: yehuozhili
|
* @Author: yehuozhili
|
||||||
* @Date: 2021-07-07 14:35:38
|
* @Date: 2021-07-07 14:35:38
|
||||||
* @LastEditors: yehuozhili
|
* @LastEditors: yehuozhili
|
||||||
* @LastEditTime: 2021-08-03 11:01:06
|
* @LastEditTime: 2021-08-05 15:10:31
|
||||||
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\registComponents\button.tsx
|
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\registComponents\button.tsx
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -102,14 +102,12 @@ const MButton = new ComponentItemFactory(
|
|||||||
createPannelOptions<FormMap, 'input'>('input', {
|
createPannelOptions<FormMap, 'input'>('input', {
|
||||||
receive: 'text',
|
receive: 'text',
|
||||||
label: '文字',
|
label: '文字',
|
||||||
text: 'yehuozhili',
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
fn: [
|
fn: [
|
||||||
createPannelOptions<FormMap, 'switch'>('switch', {
|
createPannelOptions<FormMap, 'switch'>('switch', {
|
||||||
receive: 'op1',
|
receive: 'op1',
|
||||||
label: '改变文本函数',
|
label: '改变文本函数',
|
||||||
value: false,
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})],
|
animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})],
|
||||||
|
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* @Author: yehuozhili
|
||||||
|
* @Date: 2021-08-05 10:50:57
|
||||||
|
* @LastEditors: yehuozhili
|
||||||
|
* @LastEditTime: 2021-08-05 15:10:46
|
||||||
|
* @FilePath: \dooringx\packages\dooringx-example\src\plugin\registComponents\inputCo.tsx
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Input } from 'antd';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { ComponentItemFactory, createPannelOptions, UserConfig } from 'dooringx-lib';
|
||||||
|
import { FormMap } from '../formTypes';
|
||||||
|
import { IBlockType } from '../../../../dooringx-lib/dist/core/store/storetype';
|
||||||
|
import Store from '../../../../dooringx-lib/dist/core/store';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
interface InputProps {
|
||||||
|
data: IBlockType;
|
||||||
|
context: string;
|
||||||
|
store: Store;
|
||||||
|
config: UserConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputTemp = (pr: InputProps) => {
|
||||||
|
const { props } = pr.data;
|
||||||
|
const data = pr.data;
|
||||||
|
const dataCenter = pr.config.getDataCenter();
|
||||||
|
const eventCenter = pr.config.getEventCenter();
|
||||||
|
|
||||||
|
const [value, setValue] = useState('');
|
||||||
|
const [err, setErr] = useState('');
|
||||||
|
useEffect(() => {
|
||||||
|
let unregist = () => {};
|
||||||
|
if (props.op1) {
|
||||||
|
const functionCenter = eventCenter.getFunctionCenter();
|
||||||
|
unregist = functionCenter.register(
|
||||||
|
`${pr.data.id}+验证已填函数`,
|
||||||
|
async (_ctx, next, _config, _args: any, _eventList, _iname) => {
|
||||||
|
if (value === '') {
|
||||||
|
setErr(props.warnning);
|
||||||
|
} else {
|
||||||
|
setErr('');
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: '验证已填函数',
|
||||||
|
data: [],
|
||||||
|
options: {
|
||||||
|
receive: '_changeval',
|
||||||
|
multi: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
unregist();
|
||||||
|
};
|
||||||
|
}, [value, props.warnning, props.op1]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let unregist = () => {};
|
||||||
|
if (props.op2) {
|
||||||
|
const functionCenter = eventCenter.getFunctionCenter();
|
||||||
|
unregist = functionCenter.register(
|
||||||
|
`${pr.data.id}+获取输入数据`,
|
||||||
|
async (ctx, next, _config, args: any, _eventList, _iname) => {
|
||||||
|
const key = args['_changeval'][0];
|
||||||
|
ctx[key] = value;
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: '获取数据至上下文',
|
||||||
|
data: ['ctx'],
|
||||||
|
options: {
|
||||||
|
receive: '_changeval',
|
||||||
|
multi: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
unregist();
|
||||||
|
};
|
||||||
|
}, [value, props.op2]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
zIndex: data.zIndex,
|
||||||
|
width: data.width,
|
||||||
|
height: data.height,
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
value={value}
|
||||||
|
type={props.type}
|
||||||
|
placeholder={props.placeholder}
|
||||||
|
style={{ height: 'calc( 100% - 20px )' }}
|
||||||
|
onChange={(e) => {
|
||||||
|
setValue(e.target.value);
|
||||||
|
}}
|
||||||
|
></Input>
|
||||||
|
|
||||||
|
<div style={{ height: '20px', color: 'red', fontSize: '12px' }}>{err}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const InputCo = new ComponentItemFactory(
|
||||||
|
'input',
|
||||||
|
'输入组件',
|
||||||
|
{
|
||||||
|
style: [
|
||||||
|
createPannelOptions<FormMap, 'input'>('input', {
|
||||||
|
receive: 'placeholder', //用于发送回的props,必传 ,跨组件传递需要指定额外字
|
||||||
|
label: '文本',
|
||||||
|
}),
|
||||||
|
createPannelOptions<FormMap, 'input'>('input', {
|
||||||
|
receive: 'warnning', //用于发送回的props,必传 ,跨组件传递需要指定额外字
|
||||||
|
label: '验证消息',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
fn: [
|
||||||
|
createPannelOptions<FormMap, 'switch'>('switch', {
|
||||||
|
receive: 'op1',
|
||||||
|
label: '开启验证函数',
|
||||||
|
}),
|
||||||
|
createPannelOptions<FormMap, 'switch'>('switch', {
|
||||||
|
receive: 'op2',
|
||||||
|
label: '开启获取文本函数',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})],
|
||||||
|
actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
syncList: ['synckey'],
|
||||||
|
props: {
|
||||||
|
type: 'text',
|
||||||
|
placeholder: '请输入',
|
||||||
|
warnning: '输入框不可为空',
|
||||||
|
op1: false,
|
||||||
|
op2: false,
|
||||||
|
},
|
||||||
|
width: 200,
|
||||||
|
height: 55,
|
||||||
|
},
|
||||||
|
(data, context, store, config) => {
|
||||||
|
return <InputTemp data={data} context={context} store={store} config={config}></InputTemp>;
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
export default InputCo;
|
@@ -151,6 +151,8 @@ MIT
|
|||||||
|
|
||||||
## Todo
|
## Todo
|
||||||
|
|
||||||
|
动画部分重构
|
||||||
|
|
||||||
函数部分重构
|
函数部分重构
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user