ModalForm组件:
const formRef = useRef<any>();
<ModalForm
key={51}
title='数据仓库'
formRef={formRef} // 用于获取表单数据
autoFocusFirstInput // 自动对话框打开后,首个表单项自动获得焦点
width="33%"
modalProps={{ // 扩展ant modal属性
destroyOnClose: true, // 关闭时销毁 Modal 里的子元素
onCancel: () => setVisible(false), // 取消按钮回调
open: visible, // 对话框是否可见
afterClose: async () => {
const res = await getTreeNodes();
if (res.status === 'success') {
if (JSON.stringify(res?.data) != '{}') { // 判断数据源是否为空对象
setVisible(false);
} else {
setVisible(true);
message.error('请先添加数据源');
}
}
},// 关闭后的回调
maskClosable: false, // 点击蒙层是否允许关闭
}}
onFinish={async (values) => {
const res = await getDataSource(dataSourceId);
if (res.code === 200) {
setVisible(false);
// 更新树
getTreeData();
message.success('切换成功');
}
}}
// 开启grid布局
layout="horizontal"
grid={true}
>
<ProFormGroup>
<ProFormSelect
key={52}
label="数据源类型"
name="originType"
placeholder="请选择"
rules={[{ required: true }]}
labelCol={{ span: 4 }}
options={dataType2}
initialValue={dataList?.dsType}
fieldProps={{
onChange: (value, option:any) => {
// 通过formRef.current?.setFieldsValue来清除某个表单项的值
formRef.current?.setFieldsValue({
origin: undefined,
});
setDatatype3([]);
GainDataSource(value);
},
}}
/>
</ProFormGroup>
<ProFormGroup>
<ProFormSelect
key={53}
label="数据源"
name="origin"
placeholder="请选择"
rules={[{ required: true }]}
labelCol={{ span: 4 }}
options={dataType3}
initialValue={dataList?.dsName}
fieldProps={{
onChange: (value, option:any) => {
setDataSourceId(value);
},
}}
/>
</ProFormGroup>
</ModalForm>
通过 Input 组件实现: 可新增,编辑,删除的tag组件:
// 这里是封装的Tags.tsx组件
import {forwardRef, useImperativeHandle, useState} from 'react';
import {Button, Input, message} from "antd";
import { MinusCircleOutlined } from '@ant-design/icons';
import style from './index.less';
import {updateTableTag} from "@/pages/dataDev/metaMgr/service";
const Tags = forwardRef((props, ref) => {
const [tags, setTags] = useState<any>([]);
const [parentTags, setParentTags] = useState<any>();
const [tagName, setTagName] = useState<string>(''); // 输入框的值
const [show, setShow] = useState<boolean>(true);
const [show2, setShow2] = useState<boolean>(true);
const [show3, setShow3] = useState<boolean>(false);
const [show4, setShow4] = useState<boolean>(false);
useImperativeHandle(ref, () => ({
showModal: (record: any) => {
setParentTags(record);
if (record?.tags != null && record?.tags != '') {
setTags(record?.tags.split('|'));
} else {
setTags([]);
}
}
}));
/*请求方法*/
const Request = async (type:string,id:any,tags:any) => {
const res = await updateTableTag({id:id, tags:tags});
if (res.code == 200) {
if (type == 'add') {
message.success('保存成功');
} else {
message.success('删除成功');
}
props?.getList(); // 触发父组件的getList方法
} else {
if (type == 'add') {
message.error('保存失败');
} else {
message.error('删除失败');
}
}
}
/*新增*/
const addTag = () => {
setShow2(false);
setShow(false);
setShow4(true);
/*const newTags: any = {
id: new Date().getTime() + 1 + '',
name: tagName
};*/
const newTags: any = tagName;
setTags([...tags, newTags]);
setTagName('');
}
/*保存*/
const saveTag = async () => {
setShow(true);
setShow2(true);
setShow3(false);
setShow4(false);
const newTags = tags.filter((item:any) => item !== '');
setTags(newTags);
Request('add',parentTags?.id,newTags.join('|'));
}
/*删除*/
const deleteTag = (value:any) => {
const newTags = tags.filter((item:any) => item !== value);
setTags(newTags);
Request('delete',parentTags?.id,newTags.join('|'));
}
/*赋值*/
const changeTag = (e:any, value:any) => {
const newTags = tags.map((item:any) => {
if (item == value) {
item = e.target.value;
}
return item;
})
setTags(newTags);
}
/*取消*/
const onCancel = () => {
setShow(true);
setShow2(true);
setShow3(false);
setShow4(false);
const newTags = tags.filter((item:any) => item !== '');
setTags(newTags);
setTags(parentTags?.tags.split('|')); // 点击取消时, 将父组件的tags值还原
}
return (
<div key={1} style={{margin: '2% 0'}}>
<div key={2} className={style.box}>
<span key={3} className={style.tagText}>标签: </span>
<div key={4} className={style.tagBox}>
{
tags?.map((item:any,index:any) => {
return (
<div key={index} style={{position: 'relative', margin: '0 6px'}}>
<Input key={6} size="small" value={item} disabled={show} style={{width: '100px'}} onChange={(e) => changeTag(e,item) } />
{show2 == true ?
<MinusCircleOutlined key={7} className={style.mco} onClick={() => {deleteTag(item);}} />
: null
}
</div>
)
})
}
<Button key="add" size='small' type="ghost" disabled={show3} onClick={addTag}>+</Button>
<Button key="submit" size='small' type="dashed" disabled={show4} style={{margin: '0 8px'}} onClick={() => {setShow3(true);setShow(false);}}>编辑</Button>
<Button key="cancel" size='small' style={{marginRight: '8px'}} onClick={onCancel}>取消</Button>
<Button key="back" size='small' type="primary" onClick={saveTag}>保存</Button>
</div>
</div>
</div>
);
});
export default Tags;
核心代码:
// 因为react跟vue不一样,vue的数据可以双向绑定,但是react不可行,所以这里的input回显之后,再输入的话需要我们再处理一下
/*Input赋值*/
const changeTag = (e:any, value:any) => { // e.target.value是输入框的值
const newTags = tags.map((item:any) => { // item是数组中的每一项
if (item == value) { // 如果数组中的某一项等于输入框的值, 就将该项的值改为输入框的值
item = e.target.value; // 将输入框的值赋值给数组中的某一项
}
return item; // 返回数组中的每一项
})
setTags(newTags); // 将新的数组赋值给tags
}
// 父组件中使用 Tags.tsx组件
import Tags from './Tags'; // 引入 Tags.tsx
const cRef = useRef<any>(null); // 用于获取子组件实例
/*子组件触发*/
const getTags = () => {
getTableInfo(tableId);
}
// 在需要的地方进行调用
setTimeout(() => { // 这里的定时器是为了解决调用Tags组件时,Tags组件还没有创建,而引发的问题
cRef.current?.showModal(res?.data); // 通过ref调用showModal方法,给标签组件传值
}, 50);
// getList是父组件传递给子组件的方法 getTags是子组件传递给父组件的方法
<Tags key={50} ref={cRef} getList={getTags} />