需求:要求点击按钮增加一行,增加的一行部分字段可以设置初始值,剩余未填写的字段空白,可以手动输入,也可以点击地图获取坐标后自动填入,还可以根据选择某一个列表的数据,选择完成后自动合并。
分析:所有的操作都是对目标列表的数据源的修改,本质是维护一个数组。将数据源放在全局里,每次修改都修改全局的状态,取值也是全局的状态,便于数据通信。
import React, { useContext, useEffect, useRef, useState } from 'react';
import styles from './index.less';
import { Button, Form, Input, Popconfirm, Table } from 'antd';
import { useSelector, useDispatch } from 'umi';
import { PlusOutlined } from '@ant-design/icons';
const EditableContext = React.createContext(null);
//------------
const EditableRow = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
const EditableCell = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
...restProps
}) => {
const [editing, setEditing] = useState(false);
const inputRef = useRef(null);
const form = useContext(EditableContext);
useEffect(() => {
if (editing) {
inputRef.current.focus();
}
}, [editing]);
// 编辑开关
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({
[dataIndex]: record[dataIndex],
});
};
// 保存编辑后的状态
const save = async () => {
try {
const values = await form.validateFields();
toggleEdit();
handleSave({ ...record, ...values });
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{
margin: 0,
}}
name={dataIndex}
// rules={[
// {
// required: true,
// message: `${title} is required.`,
// },
// ]}
>
<Input ref={inputRef} onPressEnter={save} onBlur={save} style={{width: '100px',height: '38px'}}/>
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{
// paddingRight: 24,
}}
onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
const LastTable = () => {
const dispatch = useDispatch();
const baseLast = useSelector((state) => state.addPath.baseLast);
const baseLastTable = useSelector((state) => state.addPath.baseLastTable)
console.log(baseLast,'baseLast')
// ----------- antd
const saveTableData = (data) => {
dispatch({
type: 'addPath/saveBaseLastTable',
payload: data,
});
}
// 这里是判断坐标选点后,并且判断列表的最后一行的值为空,将数据合并
// 当用户添加多行后才进行选点操作,判断最后一行为空,有bug,需要使用遍历,当遍历到目标值为空就进行合并操作
useEffect(() => {
if(baseLastTable.length !=0 && baseLastTable[baseLastTable.length-1].lastLa =='') {
let transData = JSON.parse(JSON.stringify(baseLastTable))
transData[transData.length-1].lastLa=baseLast.lastLa
transData[transData.length-1].lastLg=baseLast.lastLg
saveTableData(transData)
}
},[baseLast])
const handleDelete = (key) => {
const newData = baseLastTable.filter((item) => item.key !== key);
saveTableData(newData)
};
const defaultColumns = [
{
title: '序号',
dataIndex: 'order',
width:'50px'
},
{
title: '阵地名称',
dataIndex: 'name',
// editable: true, // 编辑开关
width:'100px'
},
{
title: '经度',
dataIndex: 'lastLg',
// editable: true,
},
{
title: '纬度',
dataIndex: 'lastLa',
// editable: true,
},
{
title: '操作',
dataIndex: 'operation',
render: (_, record) =>
baseLastTable.length >= 1 ? (
<Popconfirm
title="是否确认删除?"
onConfirm={() => handleDelete(record.key)}
>
<a>删除</a>
</Popconfirm>
) : null,
},
];
const handleAdd = (type) => {
const newData = {
key: baseLastTable.length+1,
order: baseLastTable.length+1,
name:'输入',
lastLg: '',
lastLa: '',
};
saveTableData([...baseLastTable, newData])
dispatch({
type: 'addPath/saveIfShow',
payload: type,
});
};
// 更新数据源
const handleSave = (row) => {
const newData = [...baseLastTable];
const index = newData.findIndex((item) => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
saveTableData(newData)
};
// 传给table
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
const columns = defaultColumns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave,
}),
};
});
return (
<div className={styles.timeTable}>
<div className={styles.startBox}>
<div className={styles.start}>终点</div>
{/* <div className={styles.icon} onClick={ () => handleAdd('last')}>
<PlusOutlined/>
</div> */}
</div>
<Table
components={components}
rowClassName={() => 'editable-row'}
bordered
dataSource={baseLastTable}
columns={columns}
pagination={false}
/>
</div>
);
};
export default LastTable;
这里只写了动态添加行,和坐标选取后的操作。在某一列表选取数据后,只需要合并数据源dispatch到全局状态即可。