Перетаскивание компонентов: использование React DnD

React.js

Статья начала мой личный блог:Оригинальная ссылка

учитьсяReact DnDПервоначальная причина заключалась в том, чтобы прочитать"Как написать компонент календаря с перетаскиванием"Когда я приложил исходный код, я не мог понять соответствующий код компонента React DnD с перетаскиванием, поэтому я очень энергично изучил компонент React DnD.

В этой статье объясняется, как использовать самое простое перетаскивание React DnD, показывая пример выбрасывания мусора (Box.jsx) в корзину (Dustbin.jsx) в корневом компоненте (Container.jsx).

предварительный просмотрэффект мусорного бака

ПроверятьИсходный код корзины

Основной API

Если вы хотите использовать его гибко, вам нужно сначала узнать несколько основных API.

  • DragSourceИспользуется для обертывания компонента, который нужно перетащить, чтобы компонент можно было перетаскивать (сделать его перетаскиваемым)
  • DropTargetИспользуется для переноса компонента, который получает перетаскиваемый элемент, чтобы компонент можно было перетащить на него.
  • DragDropContexИспользуется для обертывания корневого компонента перетаскивания,DragSourceиDropTargetнужно завернуть вDragDropContexВнутри
  • DragDropContextProviderиDragDropContexпохоже наDragDropContextProviderЭлемент оборачивает корневой компонент перетаскивания.

После примерного понимания концепций этих API код для выбрасывания мусора (Box.jsx) в корзину (Dustbin.jsx) будет таким:

// Box.jsx
import { DragSource } from 'react-dnd';

@DragSource(type, spec, collect)
export default class Box {
  /* ... */
}

// Dustbin.jsx
import { DropTarget } from 'react-dnd';

@DropTarget(types, spec, collect)
export default class Contaier {
  /* ... */
}

// Contaier.jsx (DragDropContex)
import { DragDropContext } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import Box from './Box';
import Dustbin from './Dustbin';

@DragDropContext(HTML5Backend)
export default class Contaier extends Component {
  render() {
    return (
      <div>
          <Dustbin/>
          <Box/>
      </div>
    );
  }
}

// 也可以写成 Contaier.jsx (DragDropContextProvider)
import { DragDropContextProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import Box from './Box';
import Dustbin from './Dustbin';

export default class DustbinContaier extends Component {
  render() {
    return (
      <DragDropContextProvider backend = { HTML5Backend }>
        <div>
            <Dustbin/>
            <Box/>
        </div>
      </DragDropContextProvider>
    );
  }
}

Введение в параметры API

код выше

@DragSource(type, spec, collect)
@DropTarget(types, spec, collect)

можно увидетьDragSource, DropTargetЕсть три параметра:

  • тип: тип перетаскивания, требуется
  • spec: объект метода события перетаскивания, обязательный.
  • собирать: вводить информацию, необходимую во время процесса перетаскивания, в реквизиты компонента и получать два параметраconnect and monitor, обязательный.

Следующее соглашениеисходный компонентКомпонент, упакованный для DragSource (Box.jsx в этом примере),целевой компонентКомпонент, который является оболочкой для DropTarget (Dustbin.jsx в этом примере).

type

когдаsource组件тип иtarget组件Когда тип тот же,target组件приемлемыйsource组件.

Тип типа может быть строкой, символом или функцией для возврата других реквизитов компонента.

Переведено в код:

// ItemTypes.js 定义类型
export default {
  BOX: 'box',
}

// Box.jsx
import ItemTypes from './ItemTypes'
@DragSource(ItemTypes.BOX, spec, collect)

// Dustbin.jsx
import ItemTypes from './ItemTypes'
@DropTarget(ItemTypes.BOX, spec, collect)

spec

spec определяет объект с помощью определенного метода, напримерsource组件Спецификацию можно определитьтягасвязанные события,target组件Спецификацию можно определитьместоСвязанные события, конкретный список:

DragSource specObj

  • beginDrag(props, monitor, component): событие срабатывает при начале перетаскивания,должен. Возвращает объект, связанный с реквизитом.

  • endDrag(props, monitor, component): Событие запускается при перетаскивании концов, необязательно.

  • canDrag(props, monitor): Является ли текущее перетаскиваемое событие необязательным.

  • isDragging(props, monitor): событие, срабатывающее при перетаскивании, необязательно.

Переведено в код:

  // Box.jsx
  const sourceSpec = {
    beginDrag(props, monitor, component){
      // 返回需要注入的属性
      return {
        id: props.id
      }
    },
    endDrag(props, monitor, component){
      // ..
    },
    canDrag(props, monitor){
      // ..
    },
    isDragging(props, monitor){
      // ..
    }
  }
  @DragSource(ItemTypes.BOX, sourceSpec, collect)

DropTarget specObj

  • drop(props, monitor, component)Событие, возникающее при удалении компонента, необязательно.
  • hover(props, monitor, component)Событие, на которое отвечает компонент, когда он находится над DropTarget, необязательно.
  • canDrop(props, monitor)Событие, которое срабатывает, когда компонент может быть размещен, необязательно.

Переведено в код:

// Dustbin.jsx
const targetSpec = {
  drop(props, monitor, component){
    // ..
  },
  hover(props, monitor, component){
    // ..
  },
  canDrop(props, monitor){
    // ..
  }
}
@DropTarget(ItemTypes.BOX, targetSpec, collect)

Параметры, связанные с методом объекта SpecObj

  • props: текущий реквизит компонента
  • монитор: Запросите текущее состояние перетаскивания, например, текущий перетаскиваемый элемент и его тип, текущее перетаскиваемое смещение и отбрасывается ли он в данный момент. Для получения информации о конкретных методах получения см.раздел монитора сбора параметров
  • компонент: текущий экземпляр компонента

collect

collect — это функция, которая по умолчанию принимает два параметра:connectиmonitor. Функция collect вернет объект, который будет внедрен в props компонента, то есть мы можем передатьthis.propsПолучить все свойства, возвращаемые функцией collect.

подключение параметра

  • source组件подключить в сбореDragSourceConnector, который имеет два встроенных метода:dragSource()иdragPreview().dragSource()вернуть метод, который будетsource组件Передайте этот метод, чтобы соединить исходный DOM с бэкэндом React DnD;dragPreview()Возвращает метод, в котором вы можете передать узел в качестве символа для предварительного просмотра перетаскивания.
  • target组件подключить в сбореDropTargetConnectorЭкземпляры встроенных методовdropTarget()соответствоватьdragSource(), который возвращает метод, который может подключить цель перетаскивания к серверной части React DnD.

Переведено в код:

// Box.jsx
@DragSource(ItemTypes.BOX, sourceSpec,(connect)=>({
  connectDragSource: connect.dragSource(),
  connectDragPreview: connect.dragPreview(),
}))
export default class Box {
  render() {
    const { connectDragSource } = this.props
    return connectDragSource(
      <div>
       {
           /* ... */
         }
      </div>,
    )
  }
}

// Dustbin.jsx
@DropTarget(ItemTypes.BOX, targetSpec, (connect)=>{
  connectDropTarget: connect.dropTarget(),
})
export default class Dustbin {
  render() {
    const { connectDropTarget } = this.props
    return connectDropTarget(
      <div>
       {
           /* ... */
         }
      </div>,
    )
  }
}

монитор параметров

монитор используется для запроса текущего состояния перетаскивания, и его соответствующий экземпляр имеет множество встроенных методов.

Список встроенных методов:

// DragSourceMonitor
monitor.canDrag()        // 是否能被拖拽
monitor.isDragging()      // 是否正在拖拽
monitor.getItemType()     // 拖拽组件type
monitor.getItem()         // 当前拖拽的item
monitor.getDropResult()   // 查询drop结果
monitor.didDrop()         // source是否已经drop在target
monitor.getInitialClientOffset()   // 拖拽组件初始拖拽时offset
monitor.getInitialSourceClientOffset()
monitor.getClientOffset() // 拖拽组件当前offset
monitor.getDifferenceFromInitialOffset() // 当前拖拽offset和初始拖拽offset的差别
monitor.getSourceClientOffset()

// DropTargetMonitor
monitor.canDrop()         // 是否可被放置
monitor.isOver(options)   // source是否在target上方
monitor.getItemType()     // 拖拽组件type
monitor.getItem()         // 当前拖拽的item
monitor.getDropResult()   // 查询drop结果
monitor.didDrop()         // source是否已经drop在target
monitor.getInitialClientOffset()   // 拖拽组件初始拖拽时offset
monitor.getInitialSourceClientOffset()
monitor.getClientOffset() // 拖拽组件当前offset
monitor.getDifferenceFromInitialOffset() // 当前拖拽offset和初始拖拽offset的差别
monitor.getSourceClientOffset()

конкретный пример

Во-первых, поскорее оставьте официальный пример и исходный код: