最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【已解决】Reactjs的Antd Pro中实现表格中支持可编辑的单元格

JS crifan 1634浏览 0评论
折腾:
【未解决】Antd Pro的ReactJS中实现既可以编辑单元格值又可以拖动排序的表格
期间,需要先去合并进来,使得Reactjs的Antd Pro中的Table中的cell是可以编辑值的。
经过一番折腾,参考:
https://ant.design/components/table-cn/#components-table-demo-edit-cell
中的示例代码。
【总结】
最后用代码:
src/components/EditableCell/index.js
import React, { PureComponent } from 'react';
import styles from './index.less';
import { Form, Input } from 'antd';

const FormItem = Form.Item;
const EditableContext = React.createContext();

const EditableRow = ({ form, index, ...props }) => (
  <EditableContext.Provider value={form}>
    <tr {...props} />
  </EditableContext.Provider>
);

export const EditableFormRow = Form.create()(EditableRow);

// export default class EditableCell extends PureComponent {
export class EditableCell extends PureComponent {

  state = {
    editing: false,
  }

  componentDidMount() {
    console.log("EditableCell componentDidMount: this.props.editable", this.props.editable)

    if (this.props.editable) {
      document.addEventListener('click', this.handleClickOutside, true);
    }
  }

  componentWillUnmount() {
    if (this.props.editable) {
      document.removeEventListener('click', this.handleClickOutside, true);
    }
  }

  toggleEdit = () => {
    console.log("toggleEdit=")
    console.log("this.state.editing=", this.state.editing)

    const editing = !this.state.editing;
    this.setState({ editing }, () => {
      if (editing) {
        this.input.focus();
      }
    });
  }

  handleClickOutside = (e) => {
    const { editing } = this.state;
    if (editing && this.cell !== e.target && !this.cell.contains(e.target)) {
      this.save();
    }
  }

  save = () => {
    console.log("save")
    const { record, handleSave } = this.props;
    console.log("record=", record)
    this.form.validateFields((error, values) => {
      console.log("form.validateFields=: error", error, ", values=", values)

      if (error) {
        return
      }
      this.toggleEdit();
      handleSave({ ...record, ...values });
    });
  }

  render() {
    const { editing } = this.state;

    const {
      editable,
      dataIndex,
      title,
      record,
      index,
      // handleSave,
      ...restProps
    } = this.props;

    console.log("editing=", editing, ", editable=", editable, ", record=", record)

    return (
      <td ref={node => (this.cell = node)} {...restProps}>
        {editable ? (
          <EditableContext.Consumer>
            {(form) => {
              console.log("EditableContext.Consumer: form=", form)

              this.form = form;
              return (
                editing ? (
                  <FormItem style={{ margin: 0 }}>
                    {form.getFieldDecorator(dataIndex, {
                      rules: [{
                        required: true,
                        message: `${title} is required.`,
                      }],
                      initialValue: record[dataIndex],
                    })(
                      <Input
                        ref={node => (this.input = node)}
                        onPressEnter={this.save}
                      />
                    )}
                  </FormItem>
                ) : (
                  <div
                    className={styles.editableCellValueWrap}
                    // className={styles.nonEditableCellValueWrap}
                    style={{ paddingRight: 5 }}
                    onClick={this.toggleEdit}
                  >
                    {restProps.children}
                  </div>
                )
              );
            }}
          </EditableContext.Consumer>
        ) : restProps.children}
      </td>
    );
  }
}
src/components/EditableCell/index.less
@import '~antd/lib/style/themes/default.less';

.editable-cell {
  position: relative;
}

// .nonEditableCellValueWrap {
//   padding: 5px 12px;
//   cursor: pointer;
//   background: grey;
// }

.editableCellValueWrap {
  padding: 5px 12px;
  // padding: 2px 4px;
  cursor: pointer;
}

// .editable-row:hover .editableCellValueWrap {
// .editableRow:hover .editableCellValueWrap {
.editableCellValueWrap:hover {
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  padding: 4px 11px;
  // padding: 2px 4px;
}
调用:
src/routes/Script/ScriptCreate.js
import React, { PureComponent } from 'react';
import { connect } from 'dva';
import { routerRedux } from 'dva/router';
import {
  Col,
  Form,
  Input,
  Button,
  Card,
  InputNumber,
  Select,
  message,
  Modal,
} from 'antd';
import PageHeaderLayout from '../../layouts/PageHeaderLayout';

import { EditableCell, EditableFormRow} from '../../components/EditableCell'


import { Table } from 'antd';
...
const FormItem = Form.Item;
const InputGroup = Input.Group;
const { TextArea } = Input;
const { Option } = Select;

...

const columns = [
  // {
  //   title: 'Name',
  //   dataIndex: 'name',
  //   key: 'name',
  // }, {
  //   title: 'Age',
  //   dataIndex: 'age',
  //   key: 'age',
  // }, {
  //   title: 'Address',
  //   dataIndex: 'address',
  //   key: 'address',
  // },
  {
    title: '序号',
    width: "10%",
    dataIndex: 'number',
    key: 'number',
    // rowKey: 'number',
    // fixed: 'left',
    render(text, record, index) {
      return index + 1;
    },
  },
  {
    width: "15%",
    editable: true,
    title: 'Speaker/Song',
    dataIndex: 'speakerOrSong',
    key: 'speakerOrSong',
  },
  {
    width: "75%",
    editable: true,
    title: 'Content/Name',
    dataIndex: 'contentOrName',
    key: 'contentOrName',
  },
];

/* eslint-disable */
@DragDropContext(HTML5Backend)
class DragableOrEditableTable extends 
React.Component
 {
  state = {
    itemList: [],
  }

  constructor(props){
    super(props)
    console.log("DragableOrEditableTable constructor: props=", props)

    console.log("this.props.itemList=", this.props.itemList)

    this.handleSaveEditableCell = this.handleSaveEditableCell.bind(this)

    this.state.itemList = this.props.itemList;
  }

  components = {
    body: {
      row: EditableFormRow,
      cell: EditableCell,
    },
  }

  handleSaveEditableCell = (row) => {
    console.log("handleSaveEditableCell: row=", row)

    const newData = [...this.state.itemList];
    console.log("newData=", newData)
    const index = newData.findIndex(item => row.key === item.key);
    console.log("index=", index)
    const item = newData[index];
    console.log("item=", item)
    newData.splice(index, 1, {
      ...item,
      ...row,
    });
    console.log("newData=", newData)
    this.setState({ itemList: newData });
    console.log("this.state.itemList=", this.state.itemList)
  }

  render() {
    console.log("DragableOrEditableTable render: this.state.itemList=", this.state.itemList)

    const curColumns = columns.map((col) => {
      console.log("curColumns: col=", col)

      if (!col.editable) {
        return col;
      }

      return {
        ...col,
        onCell: record => ({
          record,
          // editable: col.editable,
          editable: record.editable,
          dataIndex: col.dataIndex,
          title: col.title,
          form: this.props.form,
          handleSave: this.handleSaveEditableCell,
        }),
      }
    })

    return (
      <Table
        bordered
        // rowClassName={() => 'editable-row'}
        // rowClassName={'editable-row'}
        // columns={columns}
        columns={curColumns}
        dataSource={this.state.itemList}
        components={
this.components
}
        onRow={(record, index) => ({
          index,
        })}
      />
    );
  }
}

DragableOrEditableTable.defaultProps = {
  itemList: [],
  onListChange: (newDialogList) => {},
};

/* eslint-disable */

// const DemoSortableTable = DragDropContext(HTML5Backend)(DragableOrEditableTable);
// const DragableDialogTable = DragDropContext(HTML5Backend)(DragableOrEditableTable);


@connect(({ loading, script, topic }) => ({
  submitting: loading.effects['script/submitRegularForm'],
  script,
  topic,
}))
@Form.create()
export default class ScriptCreate extends PureComponent {
  constructor(props) {
    super(props)

    this.onDialogListChange = this.onDialogListChange.bind(this)

    this.state = {
      // dialogList: [],
      dialogList: this.demoItemList,

...
    }
  }

  demoItemList = [
    {
      key: '1',
      speakerOrSong: 'A',
      contentOrName: 'hi boy',
      editable: true,
    },
    {
      key: '2',
      speakerOrSong: 'B',
      contentOrName: 'hello',
      editable: true,
    },
    {
      key: '3',
      speakerOrSong: 'A',
      contentOrName: 'what are you doing?',
      editable: true,
    },
    {
      key: '4',
      speakerOrSong: 'B',
      contentOrName: 'I am singing',
      editable: true,
    },
    {
      key: '5',
      speakerOrSong: 'Song',
      contentOrName: 'this is a apple.mp3',
      editable: false,
    },
  ]

  // DragableDialogTable = DragDropContext(HTML5Backend)(DragableOrEditableTable)
  // DragableDialogTable = DragDropContext(HTML5Backend)(DragableOrEditableTable dialogList={demoItemList})

...

  render() {
 .....

    return (
      <PageHeaderLayout
        title="新建剧本"
      >
 ....

              <DragableOrEditableTable
                itemList={this.state.dialogList}
                onListChange={this.onDialogListChange}
                form={this.props.form}
              />
....
      </PageHeaderLayout>
    );
  }
}
实现要的效果:
鼠标移动上去有边框提示可以编辑:
对于不可编辑的,没边框:
点击可以编辑的cell时,显示输入框:
可以一直输入,内容多了后,编辑时 一直往后输入,输入完成后,回车 或者点击其他区域,即可保存:
内容超过宽度时可以自动换行显示

转载请注明:在路上 » 【已解决】Reactjs的Antd Pro中实现表格中支持可编辑的单元格

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
82 queries in 0.174 seconds, using 22.17MB memory