折腾:
【未解决】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时,显示输入框:
可以一直输入,内容多了后,编辑时 一直往后输入,输入完成后,回车 或者点击其他区域,即可保存:
内容超过宽度时可以自动换行显示