您的位置:

React拖拽入门指南

一、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;
`}