From 9da9f3c783de2fd0a7eacf8906bada53b0349c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=95=8A=E4=B9=90-js?= <125586657@qq.com> Date: Sat, 22 Mar 2025 09:53:32 +0000 Subject: [PATCH] =?UTF-8?q?update=2027.=20=E9=A1=B9=E7=9B=AE=E6=89=93?= =?UTF-8?q?=E5=8C=85=E6=9E=84=E5=BB=BA/=E4=BB=A3=E7=A0=81/src/components/E?= =?UTF-8?q?ditable/index.js.=20//=20=E5=AF=BC=E5=85=A5=20React=20=E5=92=8C?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=20hooks=EF=BC=8C=E4=BB=A5=E5=8F=8A=20Ant=20D?= =?UTF-8?q?esign=20=E7=BB=84=E4=BB=B6=20import=20React,=20{=20useState,=20?= =?UTF-8?q?useRef,=20useContext,=20useEffect=20}=20from=20'react';=20impor?= =?UTF-8?q?t=20{=20Form,=20Input,=20Select,=20DatePicker=20}=20from=20'ant?= =?UTF-8?q?d';=20const=20{=20Option=20}=20=3D=20Select;=20=20//=20?= =?UTF-8?q?=E8=A7=A3=E6=9E=84=20Select=20=E7=9A=84=E5=AD=90=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=20Option=20import=20{=20mapData=20}=20from=20'utils/m?= =?UTF-8?q?apData';=20=20//=20=E5=AF=BC=E5=85=A5=E9=A2=84=E8=AE=BE?= =?UTF-8?q?=E7=9A=84=E6=98=A0=E5=B0=84=E6=95=B0=E6=8D=AE=EF=BC=88=E5=A6=82?= =?UTF-8?q?=E9=80=89=E9=A1=B9=E5=88=97=E8=A1=A8=EF=BC=89=20import=20moment?= =?UTF-8?q?=20from=20'moment';=20=20//=20=E6=97=B6=E9=97=B4=E5=A4=84?= =?UTF-8?q?=E7=90=86=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit // 创建一个 React 上下文,用于在行和单元格之间传递表单实例 const EditableContext = React.createContext(null); //- 可编辑表格行组件(包裹每一行) export const EditableRow = ({ index, ...props }) => { const [form] = Form.useForm(); // 创建表单实例 return ( // 包裹整个行的表单(不渲染实际
标签) {/* 通过上下文将表单实例传递给子组件 */} {/* 渲染表格行 */}
); }; //- 可编辑单元格组件(包裹每个单元格) export const EditableCell = ({ title, // 列标题(未直接使用) editable, // 是否可编辑 children, // 默认内容(非编辑状态显示) dataIndex, // 数据字段名(如 "name") record, // 当前行数据对象 handleSave, // 保存回调函数 rules, // 表单验证规则 type, // 输入类型(inputNode/selectNode/dateNode) ...restProps // 其他透传给 的属性 }) => { const [editing, setEditing] = useState(false); // 控制编辑状态 const inputRef = useRef(null); // 引用输入控件(用于聚焦) const form = useContext(EditableContext); // 从行组件获取表单实例 // 当进入编辑状态时自动聚焦输入控件 useEffect(() => { if (editing) { inputRef.current && inputRef.current.focus(); } }, [editing]); //- 切换编辑状态并初始化表单值 const toggleEdit = () => { setEditing(!editing); // 设置表单初始值(处理时间字段为 moment 对象) form.setFieldsValue({ [dataIndex]: record[dataIndex], onboardingTime: moment(record.onboardingTime), // 转换时间字段 date: moment(record.date), createTime: moment(record.createTime), }); }; //- 保存前的验证和提交逻辑 const _sendBeforeCheck = async () => { try { // 验证当前字段 const editData = await form.validateFields([dataIndex]); setEditing(!editing); // 退出编辑状态 // 值未变化时不触发保存 if (record[dataIndex] === editData[dataIndex]) return; // 调用外部保存逻辑 handleSave({ _id: record._id, // 行唯一标识 updateVal: editData[dataIndex], // 新值 type: dataIndex // 字段名 }); } catch (error) { setEditing(!editing); // 验证失败时退出编辑状态 } }; //- 定义不同类型的编辑控件 const editNodeData = { inputNode: ( // 文本输入框 ), selectNode: ( // 下拉选择器 ), dateNode: ( // 日期选择器 ), }; // 根据编辑状态渲染内容 let childNode = children; // 默认显示原始内容 if (editable) { childNode = editing ? ( // 编辑状态:渲染表单控件 {editNodeData[type]} {/* 根据 type 选择控件类型 */} ) : ( // 非编辑状态:点击区域触发编辑
{children} {/* 显示原始值 */}
); } // 返回表格单元格,透传所有属性(如 className/style 等) return {childNode}; }; Signed-off-by: 啊乐-js <125586657@qq.com> --- .../src/components/Editable/index.js" | 250 +++++++++--------- 1 file changed, 129 insertions(+), 121 deletions(-) diff --git "a/27. \351\241\271\347\233\256\346\211\223\345\214\205\346\236\204\345\273\272/\344\273\243\347\240\201/src/components/Editable/index.js" "b/27. \351\241\271\347\233\256\346\211\223\345\214\205\346\236\204\345\273\272/\344\273\243\347\240\201/src/components/Editable/index.js" index d7564a9..c73cae0 100644 --- "a/27. \351\241\271\347\233\256\346\211\223\345\214\205\346\236\204\345\273\272/\344\273\243\347\240\201/src/components/Editable/index.js" +++ "b/27. \351\241\271\347\233\256\346\211\223\345\214\205\346\236\204\345\273\272/\344\273\243\347\240\201/src/components/Editable/index.js" @@ -1,122 +1,130 @@ -import React, { useState, useRef, useContext, useEffect } from 'react'; -import { Form, Input, Select, DatePicker } from 'antd'; -const { Option } = Select; -import { mapData } from 'utils/mapData'; -import moment from 'moment'; - -const EditableContext = React.createContext(null); - -//- 可编辑的行 -export const EditableRow = ({ index, ...props }) => { - const [form] = Form.useForm(); - return ( -
- - - -
- ); -}; - -//- 可编辑的单元格 -export const EditableCell = ({ - title, - editable, - children, - dataIndex, - record, - handleSave, - rules, - type, - ...restProps -}) => { - const [editing, setEditing] = useState(false); - const inputRef = useRef(null); - const form = useContext(EditableContext); - - useEffect(() => { - if (editing) { - inputRef.current && inputRef.current.focus(); - } - }, [editing]); - - //- 单元格点击的时候进行内容的渲染 - const toggleEdit = () => { - setEditing(!editing); - form.setFieldsValue({ - [dataIndex]: record[dataIndex], - onboardingTime: moment(record.onboardingTime), //- 指定的时间字段的渲染操作 - date: moment(record.date), //- 指定的时间字段的渲染操作 - createTime: moment(record.createTime), //- 指定的时间字段的渲染操作 - }); - }; - - //- 修改之前的检测 - const _sendBeforeCheck = async () => { - try { - const editData = await form.validateFields([dataIndex]); - setEditing(!editing); - //- 当前修改后的值是否与之前的值相等 - if (record[dataIndex] === editData[dataIndex]) return; - handleSave({ - _id: record._id, - updateVal: editData[dataIndex], - type: dataIndex, - }); - } catch (error) { - setEditing(!editing); - } - }; - - const editNodeData = { - inputNode: ( - - ), - selectNode: ( - - ), - dateNode: ( - - ), - }; - - let childNode = children; - - if (editable) { - childNode = editing ? ( - - {editNodeData[type]} - - ) : ( -
- {children} -
- ); - } - - return {childNode}; -}; +// 导入 React 和相关 hooks,以及 Ant Design 组件 +import React, { useState, useRef, useContext, useEffect } from 'react'; +import { Form, Input, Select, DatePicker } from 'antd'; +const { Option } = Select; // 解构 Select 的子组件 Option +import { mapData } from 'utils/mapData'; // 导入预设的映射数据(如选项列表) +import moment from 'moment'; // 时间处理库 +// 创建一个 React 上下文,用于在行和单元格之间传递表单实例 +const EditableContext = React.createContext(null); + +//- 可编辑表格行组件(包裹每一行) +export const EditableRow = ({ index, ...props }) => { + const [form] = Form.useForm(); // 创建表单实例 + return ( + // 包裹整个行的表单(不渲染实际
标签) + + {/* 通过上下文将表单实例传递给子组件 */} + + {/* 渲染表格行 */} + + +
+ ); +}; + +//- 可编辑单元格组件(包裹每个单元格) +export const EditableCell = ({ + title, // 列标题(未直接使用) + editable, // 是否可编辑 + children, // 默认内容(非编辑状态显示) + dataIndex, // 数据字段名(如 "name") + record, // 当前行数据对象 + handleSave, // 保存回调函数 + rules, // 表单验证规则 + type, // 输入类型(inputNode/selectNode/dateNode) + ...restProps // 其他透传给 的属性 +}) => { + const [editing, setEditing] = useState(false); // 控制编辑状态 + const inputRef = useRef(null); // 引用输入控件(用于聚焦) + const form = useContext(EditableContext); // 从行组件获取表单实例 + + // 当进入编辑状态时自动聚焦输入控件 + useEffect(() => { + if (editing) { + inputRef.current && inputRef.current.focus(); + } + }, [editing]); + + //- 切换编辑状态并初始化表单值 + const toggleEdit = () => { + setEditing(!editing); + // 设置表单初始值(处理时间字段为 moment 对象) + form.setFieldsValue({ + [dataIndex]: record[dataIndex], + onboardingTime: moment(record.onboardingTime), // 转换时间字段 + date: moment(record.date), + createTime: moment(record.createTime), + }); + }; + + //- 保存前的验证和提交逻辑 + const _sendBeforeCheck = async () => { + try { + // 验证当前字段 + const editData = await form.validateFields([dataIndex]); + setEditing(!editing); // 退出编辑状态 + // 值未变化时不触发保存 + if (record[dataIndex] === editData[dataIndex]) return; + // 调用外部保存逻辑 + handleSave({ + _id: record._id, // 行唯一标识 + updateVal: editData[dataIndex], // 新值 + type: dataIndex // 字段名 + }); + } catch (error) { + setEditing(!editing); // 验证失败时退出编辑状态 + } + }; + + //- 定义不同类型的编辑控件 + const editNodeData = { + inputNode: ( // 文本输入框 + + ), + selectNode: ( // 下拉选择器 + + ), + dateNode: ( // 日期选择器 + + ), + }; + + // 根据编辑状态渲染内容 + let childNode = children; // 默认显示原始内容 + + if (editable) { + childNode = editing ? ( + // 编辑状态:渲染表单控件 + + {editNodeData[type]} {/* 根据 type 选择控件类型 */} + + ) : ( + // 非编辑状态:点击区域触发编辑 +
+ {children} {/* 显示原始值 */} +
+ ); + } + + // 返回表格单元格,透传所有属性(如 className/style 等) + return {childNode}; +}; \ No newline at end of file -- Gitee