Skip to content

Commit 95c05c9

Browse files
committed
feat(Table): dragable table with react-dnd
1 parent 40de21d commit 95c05c9

File tree

4 files changed

+227
-4
lines changed

4 files changed

+227
-4
lines changed

docs/table/demo/dragable.md

+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
2+
# 拖拽排序
3+
4+
- order: 24
5+
6+
可拖拽的表格。拖拽功能的实现依赖react-dnd@7.xreact-dnd-html5-backend@7.x, 它要求react react-dom 版本高于16.3.x
7+
8+
:::lang=en-us
9+
# Simple
10+
11+
- order: 24
12+
13+
Dragable table with sort. It requires react-dnd@7.x, react-dnd-html5-backend@7.x, react@16.3.x and react-dom@16.3.x
14+
:::
15+
16+
---
17+
18+
````jsx
19+
import { Table } from '@alifd/next';
20+
import { DragDropContext, DragSource, DropTarget } from 'react-dnd';
21+
import HTML5Backend from 'react-dnd-html5-backend';
22+
import classnames from 'classnames';
23+
24+
const { SelectionRow } = Table;
25+
26+
let dragingIndex = -1;
27+
28+
function MyRow (props) {
29+
const {
30+
isDragging,
31+
isOver,
32+
connectDragSource,
33+
connectDropTarget,
34+
moveRow,
35+
className,
36+
...others
37+
} = props;
38+
39+
const opacity = isDragging ? 0 : 1;
40+
const style = { ...others.style, cursor: 'move' };
41+
42+
const cls = classnames({
43+
[className]: className,
44+
'drop-over-upward': isOver && others.index < dragingIndex,
45+
'drop-over-downward': isOver && others.index > dragingIndex,
46+
});
47+
48+
return <SelectionRow {...others}
49+
style={{ ...style, ...{ opacity } }}
50+
className={cls}
51+
wrapper={(row) => connectDragSource(connectDropTarget(row))} />
52+
}
53+
54+
const NewRow = DropTarget(
55+
'row',
56+
{
57+
drop(props, monitor) {
58+
const dragIndex = monitor.getItem().index;
59+
const hoverIndex = props.index;
60+
61+
if (dragIndex === hoverIndex) {
62+
return;
63+
}
64+
65+
props.moveRow(dragIndex, hoverIndex);
66+
monitor.getItem().index = hoverIndex;
67+
},
68+
},
69+
(connect, monitor) => ({
70+
connectDropTarget: connect.dropTarget(),
71+
isOver: monitor.isOver(),
72+
}),
73+
)(
74+
DragSource(
75+
'row',
76+
{
77+
beginDrag: props => {
78+
dragingIndex = props.index;
79+
return {
80+
id: props.record[props.primaryKey],
81+
index: props.rowIndex,
82+
};
83+
},
84+
},
85+
(connect, monitor) => ({
86+
connectDragSource: connect.dragSource(),
87+
isDragging: monitor.isDragging(),
88+
}),
89+
)(MyRow),
90+
);
91+
92+
class InnerTable extends React.Component {
93+
94+
constructor(props) {
95+
super(props);
96+
this.state = {
97+
dataSource: [...props.dataSource],
98+
};
99+
}
100+
101+
componentWillReceiveProps(nextProps) {
102+
if (nextProps.dataSource && JSON.stringify(nextProps.dataSource) !==
103+
JSON.stringify(this.state.dataSource)) {
104+
this.setState({ dataSource: [...nextProps.dataSource] });
105+
}
106+
}
107+
108+
moveRow = (dragIndex, hoverIndex) => {
109+
let { onSort } = this.props;
110+
const dragRow = this.state.dataSource[dragIndex];
111+
let dataSource = [...this.state.dataSource];
112+
dataSource.splice(dragIndex, 1);
113+
dataSource.splice(hoverIndex, 0, dragRow);
114+
this.setState({
115+
dataSource,
116+
});
117+
118+
onSort && onSort(this.state.dataSource);
119+
};
120+
121+
render() {
122+
123+
let { excludeProvider, ...restProps } = this.props;
124+
const tableProps = {
125+
...restProps,
126+
dataSource: this.state.dataSource,
127+
rowProps: (props, index) => ({
128+
index,
129+
moveRow: this.moveRow,
130+
}),
131+
components: {
132+
Row: NewRow
133+
},
134+
};
135+
136+
return <Table {...tableProps} />;
137+
}
138+
}
139+
140+
141+
class SortableTable extends React.Component {
142+
render() {
143+
const ComponentName = DragDropContext(HTML5Backend)(InnerTable);
144+
return <ComponentName {...this.props} />;
145+
}
146+
}
147+
148+
149+
150+
const result = [{
151+
id: '001',
152+
time: 1951,
153+
title: {name: 'The Old Man and the Sea'},
154+
}, {
155+
id: '002',
156+
time: 1925,
157+
title: {name: 'the great gatsby'},
158+
}, {
159+
id: '003',
160+
time: 1719,
161+
title: {name: 'The adventures of Robinson Crusoe'},
162+
}];
163+
164+
class Demo extends React.Component {
165+
constructor(props) {
166+
super(props);
167+
168+
this.state = {
169+
dataSource: result,
170+
};
171+
}
172+
173+
onRemove = (id) => {
174+
const {dataSource} = this.state;
175+
let index = -1;
176+
dataSource.forEach((item, i) => {
177+
if (item.id === id) {
178+
index = i;
179+
}
180+
});
181+
if (index !== -1) {
182+
dataSource.splice(index, 1);
183+
this.setState({
184+
dataSource
185+
});
186+
}
187+
}
188+
189+
renderOper = (value, index, record) => {
190+
return <a onClick={this.onRemove.bind(this, record.id)}>Remove({record.id})</a>;
191+
};
192+
render() {
193+
return (<div>
194+
<SortableTable dataSource={this.state.dataSource}>
195+
<Table.Column title="Id" dataIndex="id" width={100} lock/>
196+
<Table.Column title="Title" dataIndex="title.name" width={400} />
197+
<Table.Column title="Time" dataIndex="time" width={300}/>
198+
<Table.Column title="operate" cell={this.renderOper} width={300} lock="right"/>
199+
</SortableTable>
200+
</div>);
201+
}
202+
}
203+
204+
205+
ReactDOM.render(<Demo />, mountNode);
206+
````
207+
````css
208+
.drop-over-downward{
209+
border-bottom: 2px dashed #3080fe;
210+
}
211+
212+
.drop-over-upward{
213+
border-top: 2px dashed #3080fe;
214+
}
215+
````

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@
7676
"shallow-element-equals": "^1.0.1"
7777
},
7878
"devDependencies": {
79-
"@types/react": "^16.8.13",
8079
"@alifd/api-extractor": "^3.4.0",
8180
"@alifd/babel-preset-next": "^2.0.0",
8281
"@alifd/doc-parser": "^1.0.0",
@@ -88,6 +87,7 @@
8887
"@no-repeat/sass-tracker": "^0.0.10",
8988
"@no-repeat/sassdoc-parser": "^0.0.11",
9089
"@octokit/rest": "^15.15.1",
90+
"@types/react": "^16.8.13",
9191
"autoprefixer": "^7.1.4",
9292
"axe-core": "^3.2.0",
9393
"babel-core": "^6.26.0",
@@ -157,6 +157,8 @@
157157
"react-copy-to-clipboard": "^5.0.1",
158158
"react-cropper": "^1.0.0",
159159
"react-dev-utils": "^4.2.1",
160+
"react-dnd": "^7.0.0",
161+
"react-dnd-html5-backend": "^7.0.0",
160162
"react-dom": "^16.0.0",
161163
"react-redux": "^5.0.7",
162164
"react-router": "^4.3.1",

scripts/server/tpls/demo.ejs

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@
4040
}
4141
</script>
4242
<script src="//shadow.elemecdn.com/npm/babel-polyfill@6.26.0/dist/polyfill.min.js"></script>
43-
<script src="//shadow.elemecdn.com/npm/react@16.0.0/umd/react.development.js"></script>
44-
<script src="//shadow.elemecdn.com/npm/react-dom@16.0.0/umd/react-dom.development.js"></script>
43+
<script src="//shadow.elemecdn.com/npm/react@16.8.3/umd/react.development.js"></script>
44+
<script src="//shadow.elemecdn.com/npm/react-dom@16.8.3/umd/react-dom.development.js"></script>
4545
<script src="//shadow.elemecdn.com/npm/moment@2.24.0/min/moment-with-locales.js"></script>
4646
<script>
4747
window.mountNode = document.getElementById('mount-node');

src/table/base/row.jsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export default class Row extends React.Component {
2525
cellRef: PropTypes.func,
2626
colGroup: PropTypes.object,
2727
locale: PropTypes.object,
28+
wrapper: PropTypes.func,
2829
};
2930

3031
static defaultProps = {
@@ -38,6 +39,7 @@ export default class Row extends React.Component {
3839
onMouseLeave: noop,
3940
cellRef: noop,
4041
colGroup: {},
42+
wrapper: row => row,
4143
};
4244

4345
static contextTypes = {
@@ -194,13 +196,15 @@ export default class Row extends React.Component {
194196
locale,
195197
expandedIndexSimulate,
196198
rtl,
199+
wrapper,
197200
...others
198201
} = this.props;
199202
const cls = classnames({
200203
[`${prefix}table-row`]: true,
201204
[className]: className,
202205
});
203-
return (
206+
207+
const tr = (
204208
<tr
205209
className={cls}
206210
role="row"
@@ -213,5 +217,7 @@ export default class Row extends React.Component {
213217
{children}
214218
</tr>
215219
);
220+
221+
return wrapper(tr);
216222
}
217223
}

0 commit comments

Comments
 (0)