折腾:
【未解决】Antd Pro的ReactJS中实现既可以编辑单元格值又可以拖动排序的表格
期间,需要先去合并进来,使得Reactjs的Antd Pro中的Table中的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时,显示输入框:


可以一直输入,内容多了后,编辑时 一直往后输入,输入完成后,回车 或者点击其他区域,即可保存:

内容超过宽度时可以自动换行显示
