React+antd实现可编辑单元格,非官网写法,不使用可编辑行和form验证

本文介绍了如何在不使用Ant Design的EditableRow和Cell以及Context、高阶组件和form验证的情况下,创建一个可编辑单元格的精简版。通过在column元素的render中使用<EditableCell>,并在props中传递保存修改的方法,可以实现简单的可编辑单元格功能。当单元格失去焦点或按下回车键后,数据将更新。为了防止数据回滚,可以在state中添加一个text字段,并用它替换{children}来显示最新内容。为了代码复用,建议将此组件单独存放在一个文件中,然后在需要的页面中导入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

antd3以上的写法乍一看还挺复杂,自己写了个精简版

没用EditableRow+Cell的结构,也不使用Context、高阶组件等,不使用form验证

最终效果:

class EditableCell extends React.Component {
    state = {
        editing: false
    };
    toggleEdit = () => {
        const editing = !this.state.editing
        this.setState({ editing }, () => {
            if (editing) {
                this.input.focus()
            }
        })
    };
    save = e => {
        const { record, handleSave } = this.props;
        this.toggleEdit();
        handleSave(record, e.target.value)

    };  // save主要处理两件事,一是切换editing状态,二是提交更新的数据
    render() {
        const { children } = this.props
        const { editing } = this.state;
        return editing ? (
            <Input defaultValue={children} ref={node=>(this.input=node)} onPressEnter={this.save} onBlur={this.save} />
        ) : (
            <span>{children}<Icon type="edit" theme='twoTone' style={{marginLeft: 10}} onClick={this.toggleEdit} /></span>
            )
    }
};

最后使用的时候直接在column元素的render里面<EditableCell> </EditableCell>就好啦, props一定要传处理保存修改的方法

render: (text, record) => {
    return (<EditableCell handleSave={handleModifyNote} record={record}>{text}</EditableCell>) //记得传props
    }

现在这个可编辑单元格组件在鼠标失焦或者回车后,列数据会变回修改前的数据,在state里面加个text,把最后显示的 {children} 换成 {text} 就可以。

该组件也许很多页面都会使用,单独放在一个文件里再引入会优雅很多:

import React from 'react';
import {Input, Icon} from 'antd';

class EditableCell extends React.Component {
    state = {
        editing: false,
        text: this.props.children
    };
    toggleEdit = () => {
        const editing = !this.state.editing
        this.setState({ editing }, () => {
            if (editing) {
                this.input.focus()
            }
        })
    };
    save = e => {
        const { record, handleSave } = this.props;
        this.setState({text: e.target.value});
        this.toggleEdit();
        handleSave(record, e.target.value)

    };
    render() {
        const { editing, text } = this.state;
        return editing ? (
            <Input defaultValue={text} ref={node=>(this.input=node)} onPressEnter={this.save} onBlur={this.save} />
        ) : (
            <span>{text}<Icon type="edit" theme='twoTone' style={{marginLeft: 10}} onClick={this.toggleEdit} /></span>
            )
    }
};

export default EditableCell;

引入的时候:

import { EditableCell } from '../EditableCell'

全部页面index.jsx大概是这样的

import React, { useEffect } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Card, Input, Select, Row, message, Col, Table, Button, Icon, Upload, Form, DatePicker } from 'antd';
import { connect } from 'dva';
import download from '@/utils/download';
import styles from './style.less';

const { Option } = Select;

class EditableCell extends React.Component {
    state = {
        editing: false
    };
    toggleEdit = () => {
        const editing = !this.state.editing
        this.setState({ editing }, () => {
            if (editing) {
                this.input.focus()
            }
        })
    };
    save = e => {
        const { record, handleSave } = this.props;
        this.toggleEdit();
        handleSave(record, e.target.value)

    };
    render() {
        const { children } = this.props
        const { editing } = this.state;
        return editing ? (
            <Input defaultValue={children} ref={node=>(this.input=node)} onPressEnter={this.save} onBlur={this.save} />
        ) : (
            <span>{children}<Icon type="edit" theme='twoTone' style={{marginLeft: 10}} onClick={this.toggleEdit} /></span>
            )
    }
};

const Aabbb = props => {
    const { form, dispatch, dataLoading } = props;
    const { getFieldDecorator } = form;
    const { pageInfo, res }  = props;
    const formItemLayout = {
        labelCol: { span: 8 },
        wrapperCol: { span: 16 },
    };
    const columns = [
        { title: '序号', dataIndex: 'id', align: 'center', width: 80, fixed: 'left', render: (text, record, index) =>
            (<span>{(pageInfo.current - 1) * pageInfo.pageSize + index + 1}</span>)
        },
        ...
        { title: '结果', dataIndex: 'results', align: 'center', render: (text, record) => (
            <Select defaultValue={text} className={styles.tableSelection} onChange={value => handleModifyResult(value, record)}>
                <Option value="正常">正常</Option>
                <Option value="异常">异常</Option>
            </Select>
        )},
        { title: '备注', dataIndex: 'notes', align: 'center', width: 120, render: (text, record) => {
            return (<EditableCell handleSave={handleModifyNote} record={record}>{text}</EditableCell>)
        }}
    ];
    const handleModifyNote = (record, value) => {
        console.log('save', {...record, notes: value})
        dispatch({})
    };
    const handleModifyResult = (value, record) => {
        dispatch({})
        console.log({...record, inspectionResults: value});
    };
    
    
    useEffect(() => {
        
    }, []);
    const queryData = () => {}
        
    return (
        <PageHeaderWrapper>
            <Card>
                <Form horizontal="true">
                    <Row>
                        <Col span={8}>
                            ...
                        </Col>   
                    </Row>
                    <Row>
                        ...
                    </Row>
                </Form>
                <Table
                    columns={columns}
                    loading={dataLoading}
                    dataSource={res}
                    rowKey={(record,index)=>index}
                    pagination={}
                    onChange={}
                    />
            </Card>
        </PageHeaderWrapper>
    );
}

export default connect(({ aabbb, loading }) => ({
    res: aabbb.res,
    dataLoading: loading.effects['aabbb/QueryAabbb'],
}))(Form.create()(Aabbb));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值