一、React拖拽事件
React中进行拖拽操作时,常用的事件有以下四种:
{`
onDragStart:拖拽开始时触发;
onDrag:拖拽中触发;
onDragEnter:拖拽目标进入时触发;
onDragLeave:拖拽目标离开时触发。
`}
我们通过操作事件中的参数,就可以实现移动元素的效果,如下面React实现拖拽小球的示例:
{`
import React, { Component } from 'react';
import './App.css';
class App extends Component {
state = {
left: 0,
top: 0
}
dragStartHandler = (event) => {
event.dataTransfer.setData("posX", event.clientX - this.state.left)
event.dataTransfer.setData("posY", event.clientY - this.state.top)
}
dragHandler = (event) => {
this.setState({
left: event.clientX - event.dataTransfer.getData("posX"),
top: event.clientY - event.dataTransfer.getData("posY")
})
}
render() {
return (
);
}
}
export default App;
`}
二、React拖拽组件
React中实现拖拽组件,可以使用第三方库react-dnd,它提供了丰富的拖拽功能,例如拖拽排序、拖拽自由布局等。
安装react-dnd:
{`
npm install --save react-dnd react-dnd-html5-backend
`}
使用示例:
{`
import React, { Component } from 'react';
import { DragSource } from 'react-dnd';
const Types = {
ITEM: 'item'
}
const itemSource = {
beginDrag(props) {
return { id: props.id }
},
}
function collect(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging(),
}
}
class Item extends Component {
render() {
const { isDragging, connectDragSource } = this.props;
return connectDragSource(
{this.props.content}
);
}
}
Item = DragSource(Types.ITEM, itemSource, collect)(Item);
export default Item;
`}
三、React拖拽自由布局
React-dnd库还提供了自由布局的功能。通过使用DragLayer和CustomDragLayer组件,我们可以实现自由拖拽组件,并在拖拽时显示组件的位置。
使用示例:
{`
import React, { Component } from 'react';
import { DragLayer } from 'react-dnd';
function getItemStyles(props) {
const { initialOffset, currentOffset } = props;
if (!initialOffset || !currentOffset) {
return {
display: 'none'
}
}
let { x, y } = currentOffset
x -= initialOffset.x
y -= initialOffset.y
const transform = `translate(${x}px, ${y}px)`
return {
transform,
WebkitTransform: transform,
}
}
class CustomDragLayer extends Component {
renderItem(item) {
return (
{item.content}
);
}
render() {
const { isDragging, item, initialOffset, currentOffset } = this.props
if (!isDragging) {
return null
}
return (
{this.renderItem(item)}
);
}
}
function collect(monitor) {
return {
item: monitor.getItem(),
initialOffset: monitor.getInitialSourceClientOffset(),
currentOffset: monitor.getSourceClientOffset(),
isDragging: monitor.isDragging(),
}
}
export default DragLayer(collect)(CustomDragLayer);
`}
四、React拖拽排序
拖拽排序是指将一组组件从当前位置移动到另外一个位置,并保持原有的顺序。React-dnd提供了Sortable功能,通过HOC(高阶组件)实现拖拽排序的功能。
使用示例:
{`
import React, { Component } from 'react'
import {SortableContainer, SortableElement, arrayMove} from 'react-sortable-hoc'
import './App.css'
const SortableItem = SortableElement(({value}) =>
{value}
);
const SortableList = SortableContainer(({items}) => {
return (
{items.map((value, index) => (
))}
);
});
class App extends Component {
state = {
items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'],
};
onSortEnd = ({oldIndex, newIndex}) => {
this.setState({
items: arrayMove(this.state.items, oldIndex, newIndex),
});
};
render() {
return
;
}
}
export default App
`}
五、React拖拽插件
React-dnd提供了很多插件,例如TouchBackend插件,让我们可以在移动端轻松实现拖拽操作。同时,通过使用HTML5Backend插件,在React Native中实现原生拖拽也是轻松的事情。
六、React拖拽top图
利用React-dnd库和react-virtualized库,我们可以实现拖拽top图。
使用示例:
{`
import React, { Component } from 'react';
import { DragLayer } from 'react-dnd';
import { List, AutoSizer } from 'react-virtualized';
function getItemStyles(props) {
const { initialOffset, currentOffset } = props;
if (!initialOffset || !currentOffset) {
return {
display: 'none'
}
}
let { x, y } = currentOffset
x -= initialOffset.x
y -= initialOffset.y
const transform = `translate(${x}px, ${y}px)`
return {
transform,
WebkitTransform: transform,
}
}
class CustomDragLayer extends Component {
renderItem(item) {
const { content, style } = item;
return (
{content}
);
}
render() {
const { isDragging, item, initialOffset, currentOffset } = this.props
if (!isDragging) {
return null
}
return (
{this.renderItem(item)}
);
}
}
function collect(monitor) {
return {
item: monitor.getItem(),
initialOffset: monitor.getInitialSourceClientOffset(),
currentOffset: monitor.getSourceClientOffset(),
isDragging: monitor.isDragging(),
}
}
class TopChart extends Component {
state = {
topNames: [
'top1',
'top2',
'top3',
'top4',
'top5',
'top6',
'top7',
'top8',
'top9',
'top10',
'top11',
'top12',
'top13',
'top14',
'top15',
'top16',
'top17',
'top18',
'top19',
'top20',
].map(name => ({ name })),
}
rowRenderer = ({ index, key, style }) => {
const chart = this.state.topNames[index];
return (
{chart.name}
);
}
render() {
return (
{({ height, width }) => (
{
const chart = this.state.topNames[fromIndex];
this.setState(prevState => ({
topNames: arrayMove(prevState.topNames, fromIndex, toIndex).map((name, index) =>
index === toIndex ? { ...chart } : { ...name }
),
}));
}}
rowGetter={({ index }) => this.state.topNames[index]}
/>
)}
)
}
}
export default TopChart;
`}
七、React拖拽排序组件
React-dnd库只提供了底层实现,如果想要更丰富的拖拽排序组件,建议使用react-beautiful-dnd库。
八、React拖拽库
除了react-dnd和react-beautiful-dnd,还有很多其他好用的React拖拽库,例如react-sortablejs、rc-drawer等。
九、React拖拽流程图选取
React中实现选取流程图的功能,可以使用第三方库react-flow。
安装react-flow:
{`
npm install --save react-flow-renderer
`}
使用示例:
{`
import React, { Component } from 'react';
import ReactFlow, {
addEdge,
removeElements,
Controls,
Background,
} from 'react-flow-renderer';
const initialElements = [
{
id: '1',
type: 'input',
data: { label: 'Input Node' },
position: { x: 0, y: 50 },
},
{
id: '2',
data: { label: 'Output Node' },
position: { x: 500, y: 50 },
type: 'output',
},
];
class App extends Component {
state = {
elements: initialElements,
};
onElementsRemove = (elementsToRemove) =>
this.setState({ elements: removeElements(elementsToRemove, this.state.elements) });
onConnect = (params) => this.setState({ elements: addEdge(params, this.state.elements) });
render() {
const { elements } = this.state;
return (
);
}
}
export default App;
`}