折腾:
【未解决】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时,显示输入框:


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

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