В этой статье подробно объясняется API и использование react-dnd, а также прилагается демонстрация для справки, в надежде оказать помощь друзьям, которые в ней нуждаются.
1. Концепция
React DnD — это набор высокоуровневых компонентов React, при его использовании вам нужно только использовать соответствующий API для обертывания целевого компонента, чтобы реализовать функцию перетаскивания или принятия перетаскиваемых элементов. Чтобы преобразовать событие перетаскивания в соответствующее состояние объекта, разработчику не нужно самостоятельно оценивать состояние перетаскивания, а нужно только выполнить соответствующую обработку в каждом атрибуте состояния в переданном объекте спецификации. Это может быть трудно понять при первом контакте, но это будет очень удобно после того, как вы действительно освоитесь с использованием.
эта статья
Demo
адрес:react-dnd-dustbin. Если полезно, добро пожаловать в Star.
2. DragSource: позволяет перетаскивать компоненты
использовать
DragSource
Оберните компонент так, чтобы его можно было перетаскивать.
Как пользоваться
import React, { Component } from 'react';
import { DragSource } from 'react-dnd';
const spec = {
beginDrag(props, monitor, component) {
// 这里 return 出去的对象属性自行选择,这里只是用 id 作为演示
return { id: props.id }
}
endDrag(props, monitor, component) {
...
}
canDrag(props, monitor) {
...
}
isDragging(props, monitor) {
...
}
}
const collect = (connect, monitor) => ({
// 这里返回一个对象,会将对象的属性都赋到组件的 props 中去。这些属性需要自己定义。
connectDropTarget: connect.dropTarget(),
id: monitor.getItem().id
})
@DragSource(type, spec, collect)
class MyComponent extends Component {
/* ... */
}
export default MyComponent;
Объяснение параметра:
- Тип: обязательный. Строка, нотация ES6 или свойства функции, которые возвращают данный компонент. Зарегистрированы только для того же типа
drop targets
будет реагировать на элементы, созданные этим источником перетаскивания - Спецификация: требуется. Простой объект JavaScript с некоторыми разрешенными методами. Он описывает, как источник перетаскивания реагирует на события перетаскивания.
- собирать: обязательно. функция сбора. Он должен возвращать простой объект для внедрения в ваш компонент. Он получает два параметра: connect и monitor.
- варианты: опционально. обычный предмет.
методы в объекте спецификации
-
beginDrag(props, monitor, component)
: Необходимые. Когда начинается перетаскивание,beginDrag
называется. Вы должны вернуть чистыйJavaScript
объект. Контент, который вы вернете, будет помещен вmonitor.getItem()
в полученном объекте. -
endDrag(props, monitor, component)
: по желанию. Когда перетаскивание останавливается,endDrag
называется. для каждогоbeginDrag
,endDrag
будет соответствовать. -
canDrag(props, monitor)
: по желанию. Используйте его, чтобы указать, разрешено ли в данный момент перетаскивание. Если вы хотите всегда разрешать это, просто пропустите этот метод. Примечание: возможно, вы не сможете позвонитьmonitor.canDrag()
Этот метод. -
isDragging(props, monitor)
: по желанию. По умолчанию только источник перетаскивания, который инициирует операцию перетаскивания, считается перетаскиванием. Примечание: возможно, вы не сможете позвонитьmonitor.isDragging()
Этот метод.
Параметры в методах props, monitor, component
-
props
: текущий компонентprops
-
monitor
:ОдинDragSourceMonitor
пример. Используйте его для запроса информации о текущем состоянии перетаскивания, такой как текущий перетаскиваемый элемент и его тип, текущие и начальные координаты и смещения, а также был ли он удален. -
component
: Если указано, это экземпляр компонента. Используйте его для доступа к базовым узлам DOM для измерения положения или размера или для вызоваsetState
и другие компонентные методы.isDragging
,canDrag
метод недоступенcomponent
этот параметр, потому что экземпляр может быть недоступен при их вызове
подключать и контролировать параметры в сборе
-
connect
: ОдинDragSourceConnector
пример. У него есть два метода: dragPreview() и dragSource().- dragSource() => (elementOrNode, options?): Общий метод, возвращает функцию, переданную компоненту для подключения исходного DOM и React DnD Backend.
- dragPreview(): возвращает функцию, которая передается компоненту для подключения узла DOM, предварительно просматриваемого при перетаскивании, с бэкэндом React DnD.
- dragSource() => (elementOrNode, options?): Общий метод, возвращает функцию, переданную компоненту для подключения исходного DOM и React DnD Backend.
-
монитор: один
DragSourceMonitor
пример. Содержит следующие методы:
метод | значение |
---|---|
canDrag() |
Можно перетащить. true, если операция перетаскивания не выполняется |
isDragging() |
тащат. true, если выполняется операция перетаскивания |
getItemType() |
Возвращает строку или символ ES6, идентифицирующий тип перетаскиваемого в данный момент элемента. Возвращает, если ни один элемент не был перетащенnull
|
getItem() |
Возвращает простой объект, представляющий текущий перетаскиваемый элемент. Каждый источник перетаскивания должен указывать его, возвращая объект из своего метода beginDrag(). Возвращает, если ни один элемент не был перетащенnull
|
getDropResult() |
Возвращает место размещения, представляющее последнюю записьdrop result объект |
didDrop() |
еслиdrop target обработанныйdrop событие, возвращает true, иначе возвращает false. Несмотря на тоtarget без возвратаdrop результат,didDrop() также вернет true. существуетendDrag() Используйте его, чтобы проверить, обработала ли какая-либо цель перетаскивания. если вendDrag() Вызывается извне, возвращает false |
getInitialClientOffset() |
Возвращает {x, y} указателя в начале текущей операции перетаскивания.client Компенсировать. Возвращает, если ни один элемент не был перетащенnull
|
getInitialSourceClientOffset() |
Возвращает, когда текущая операция перетаскивания началасьdrag source {x, y} корневого узла DOM компонентаclient Компенсировать. Возвращает, если ни один элемент не был перетащенnull
|
getClientOffset() |
Возвращает последний записанный {x, y} указателя во время выполнения операции перетаскивания.client Компенсировать. Возвращает, если ни один элемент не был перетащенnull
|
getDifferenceFromInitialOffset() |
Возвращает последнюю запись мыши, когда началась текущая операция перетаскивания.client смещение сclient {x, y} разница между смещениями. Возвращает, если ни один элемент не был перетащенnull
|
getSourceClientOffset() |
возвращениеdrag source Ожидаемый {x, y} корневого узла DOM компонентаclient Смещение, основанное на его положении в начале текущей операции перетаскивания и разнице в движении. Возвращает, если ни один элемент не был перетащенnull
|
3. DropTarget: Включить компоненты для размещения компонентов перетаскивания и падения
использовать
DropTarget
Оберните компонент так, чтобы он реагировал на перетаскивание, наведение или опускание совместимых элементов.
Как пользоваться
import React, { Component } from 'react';
import { DropTarget } from 'react-dnd';
const spec = {
drop(props, monitor, component) {
// 这里 return 出去的对象属性自行选择,这里只是用 id 作为演示
return { id: props.id }
}
hover(props, monitor, component) {
...
}
canDrop(props, monitor) {
...
}
}
const collect = (connect, monitor) => ({
// 这里返回一个对象,会将对象的属性都赋到组件的 props 中去。这些属性需要自己定义。
connectDropTarget: connect.dropTarget()
})
@DropTarget(type, spec, collect)
class MyComponent extends Component {
/* ... */
}
export default MyComponent;
Объяснение параметра:
- Тип: обязательный. Строка, нотация ES6 или свойства функции, которые возвращают данный компонент. Эта цель перетаскивания действительна только для определенных типов
drag sources
проект отвечает - Спецификация: требуется. Простой объект JavaScript с некоторыми разрешенными методами. Он описывает, как цель перетаскивания реагирует на события перетаскивания.
- собирать: обязательно. функция сбора. Он должен возвращать обычный объект реквизита для внедрения в ваш компонент. Он принимает два параметра: connect и monitor.
- варианты: опционально. обычный предмет.
методы в объекте спецификации
-
drop(props, monitor, component)
: по желанию. Вызывается, когда на цель помещается совместимый предмет. может вернутьсяundefined
или обычные предметы. Если объект возвращается, он будет результатом перетаскивания и может использоваться сmonitor.getDropResult()
полученный. -
hover(props, monitor, component)
: по желанию. Вызывается при наведении элемента на компонент. ты можешь проверитьmonitor.isOver({ shallow: true })
чтобы проверить, происходит ли наведение только на текущей цели или вложенной. -
canDrop(props, monitor)
: по желанию. Используйте это, чтобы указать, может ли цель перетаскивания принять элемент. Если вы хотите всегда разрешать это, просто пропустите этот метод.
Документация не предоставляет способ обработки входных или выходных событий намеренно. но
monitor.isOver()
Верните результат вызова из функции сбора, чтобы мы могли использоватьcomponentDidUpdateReact
Хуки-функции для обработки событий входа и выхода в компоненте.
Параметры в методах props, monitor, component
-
props
: текущий компонентprops
-
monitor
:ОдинDropTargetMonitor
пример. Используйте его для запроса информации о текущем состоянии перетаскивания, такой как текущий перетаскиваемый элемент и его тип, текущие и начальные координаты и смещения, находится ли он за текущей целью и можно ли его удалить. -
component
: Если указано, это экземпляр компонента. Используйте его для доступа к базовым узлам DOM для измерения положения или размера или для вызоваsetState
и другие компонентные методы.canDrag
метод недоступенcomponent
Этот параметр может быть недоступен для экземпляра, когда они вызываются.
подключать и контролировать параметры в сборе
-
connect
: ОдинDropTargetConnector
пример. это только одинdropTarget()
метод.-
dropTarget() => (elementOrNode)
: общий метод, возвращает функцию, которая передается компоненту для подключения целевого DOM к React DnD Backend. Любой элемент React можно пометить как удаляемый узел с помощью { connectDropTarget: connect.dropTarget() }, возвращаемого из функции сбора.
-
-
монитор: один
DropTargetMonitor
пример. Содержит следующие методы:
метод | значение |
---|---|
canDrop() |
могут быть размещены. Возвращает true, если выполняется операция перетаскивания |
isOver(options) |
drag source стоит ли наводить курсорdrop target площадь. дополнительная доставка{ shallow: true } строго проверять, только лиdrag source наведение, а не вложенные цели |
getItemType() |
Возвращает строку или символ ES6, идентифицирующий тип перетаскиваемого в данный момент элемента. возврат, если ни один элемент не был перетащенnull
|
getItem() |
Возвращает простой объект, представляющий текущий пункт перетаскивания, каждый источник сопротивления должен указывать его, возвращая объект из своего метода PUGINDRAG (). возврат, если ни один элемент не был перетащенnull
|
getDropResult() |
Возвращает место размещения, представляющее последнюю записьdrop result объект |
didDrop() |
еслиdrop target обработанныйdrop событие, возвращает true, иначе возвращает false. Несмотря на тоtarget без возвратаdrop результат,didDrop() также вернет true. существуетendDrag() Используйте его, чтобы проверить, обработала ли какая-либо цель перетаскивания. если вendDrag() Вызывается извне, возвращает false |
getInitialClientOffset() |
Возвращает {x, y} указателя в начале текущей операции перетаскивания.client Компенсировать. Возвращает, если ни один элемент не был перетащенnull
|
getInitialSourceClientOffset() |
Возвращает, когда текущая операция перетаскивания началасьdrag source {x, y} корневого узла DOM компонентаclient Компенсировать. Возвращает, если ни один элемент не был перетащенnull
|
getClientOffset() |
Возвращает последний записанный {x, y} указателя во время выполнения операции перетаскивания.client Компенсировать. Возвращает, если ни один элемент не был перетащенnull
|
getDifferenceFromInitialOffset() |
Возвращает последнюю запись мыши, когда началась текущая операция перетаскивания.client смещение сclient {x, y} разница между смещениями. Возвращает, если ни один элемент не был перетащенnull
|
getSourceClientOffset() |
возвращениеdrag source Ожидаемый {x, y} корневого узла DOM компонентаclient Смещение, основанное на его положении в начале текущей операции перетаскивания и разнице в движении. Возвращает, если ни один элемент не был перетащенnull
|
В-четвертых, DragDropContext и DragDropContextProvider.
Уведомление:Компоненты, обернутые DragSource и DropTarget, должны быть размещены: внутри корневого компонента, обернутого DragDropContext, или внутри корневого тега DragDropContextProvider.
DragDropContext
использоватьDragDropContext
Оберните корневой компонент приложения, чтобы включить React DnD.
использование
import React, { Component } from 'react';
import HTML5Backend from 'react-dnd-html5-backend';
import { DragDropContext } from 'react-dnd';
@DragDropContext(HTML5Backend)
class YourApp extends Component {
/* ... */
}
export default YourApp;
параметр
-
бэкэнд: требуется. Бэкенд React DnD. Если вы не пишете собственный, рекомендуется использовать HTML5Backend, который поставляется с React DnD.
-
контекст: бэкэнд-зависимость. Объект контекста для пользовательских бэкендов. Например, HTML5Backend может вставлять пользовательские объекты окна для сцен iframe.
DragDropContextProvider
в видеDragDropContext
В качестве альтернативы вы можете использоватьDragDropContextProvider
Element включает React DnD для приложения. иDragDropContext
Точно так же это можно сделать с помощьюbackendprop
внедрить серверную часть, но также может внедритьwindow
объект.
использование
import React, { Component } from 'react';
import HTML5Backend from 'react-dnd-html5-backend';
import { DragDropContextProvider } from 'react-dnd';
export default class YourApp extends Component {
render() {
return (
<DragDropContextProvider backend={HTML5Backend}>
/* ... */
</DragDropContextProvider>
)
}
}
параметр
-
бэкэнд: требуется. Бэкенд React DnD. Если вы не пишете собственный, рекомендуется использовать HTML5Backend, который поставляется с React DnD.
-
контекст: бэкэнд-зависимость. Объект контекста для пользовательских бэкендов. Например, HTML5Backend может вставлять пользовательские объекты окна для сцен iframe.
5. Простой пример реакции-dnd
Этот пример объясняется со ссылкой на официальный пример мусорной корзины.
Подготовка проекта
Текущий проект используетcreate-react-app
Леса построены и используютсяreact-dnd
всегда записываются с использованием синтаксиса декоратора. Поэтому сначала вам нужно добавить некоторую конфигурацию в проект.
Способ настройки включения декоратора можно найти в моей предыдущей статье:Включить синтаксис декоратора в приложении create-реагировать.
новыйcomponents
Папка, используемая для хранения записанных компонентов. новыйtypes
папка для храненияtype
Строковые константы, вtypes
Создано в каталогеindex.js
соответствует объявлению файлаtype
ценность.
types/index.js
export default {
BOX: 'box'
}
Итак, текущий проектsrc
Структура файлов в каталоге следующая:
src
├── components/
├── types/
└── index.js
├── App.js
├── index.css
└── index.js
Создайте компонент Box как DragSource
существуетcomponents
каталог, создатьBox.js
файл, пишиBox
компонент, чтобы сделать его перетаскиваемым
components/Box.js
import React from 'react';
import PropTypes from 'prop-types';
import { DragSource } from 'react-dnd';
import ItemTypes from '../types';
const style = {
border: '1px dashed gray',
backgroundColor: 'white',
padding: '0.5rem 1rem',
marginRight: '1.5rem',
marginBottom: '1.5rem',
cursor: 'move',
float: 'left',
}
const boxSource = {
/**
* 开始拖拽时触发当前函数
* @param {*} props 组件的 props
*/
beginDrag(props) {
// 返回的对象可以在 monitor.getItem() 中获取到
return {
name: props.name,
}
},
/**
* 拖拽结束时触发当前函数
* @param {*} props 当前组件的 props
* @param {*} monitor DragSourceMonitor 对象
*/
endDrag(props, monitor) {
// 当前拖拽的 item 组件
const item = monitor.getItem()
// 拖拽元素放下时,drop 结果
const dropResult = monitor.getDropResult()
// 如果 drop 结果存在,就弹出 alert 提示
if (dropResult) {
alert(`You dropped ${item.name} into ${dropResult.name}!`)
}
},
}
@DragSource(
// type 标识,这里是字符串 'box'
ItemTypes.BOX,
// 拖拽事件对象
boxSource,
// 收集功能函数,包含 connect 和 monitor 参数
// connect 里面的函数用来将 DOM 节点与 react-dnd 的 backend 建立联系
(connect, monitor) => ({
// 包裹住 DOM 节点,使其可以进行拖拽操作
connectDragSource: connect.dragSource(),
// 是否处于拖拽状态
isDragging: monitor.isDragging(),
}),
)
class Box extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired,
isDragging: PropTypes.bool.isRequired,
connectDragSource: PropTypes.func.isRequired
}
render() {
const { isDragging, connectDragSource } = this.props
const { name } = this.props
const opacity = isDragging ? 0.4 : 1
// 使用 connectDragSource 包裹住 DOM 节点,使其可以接受各种拖动 API
// connectDragSource 包裹住的 DOM 节点才可以被拖动
return connectDragSource && connectDragSource(
<div style={{ ...style, opacity }}>
{name}
</div>
);
}
}
export default Box;
Создайте компонент мусорной корзины как DropTarget
существуетcomponents
каталог, создатьDustbin.js
файл, пишиDustbin
компонент, чтобы он мог принять соответствующий компонент перетаскивания.
components/Dustbin.js
import React from 'react';
import PropTypes from 'prop-types';
import { DropTarget } from 'react-dnd';
import ItemTypes from '../types';
const style = {
height: '12rem',
width: '12rem',
marginRight: '1.5rem',
marginBottom: '1.5rem',
color: 'white',
padding: '1rem',
textAlign: 'center',
fontSize: '1rem',
lineHeight: 'normal',
float: 'left',
}
const boxTarget = {
// 当有对应的 drag source 放在当前组件区域时,会返回一个对象,可以在 monitor.getDropResult() 中获取到
drop: () => ({ name: 'Dustbin' })
}
@DropTarget(
// type 标识,这里是字符串 'box'
ItemTypes.BOX,
// 接收拖拽的事件对象
boxTarget,
// 收集功能函数,包含 connect 和 monitor 参数
// connect 里面的函数用来将 DOM 节点与 react-dnd 的 backend 建立联系
(connect, monitor) => ({
// 包裹住 DOM 节点,使其可以接收对应的拖拽组件
connectDropTarget: connect.dropTarget(),
// drag source是否在 drop target 区域
isOver: monitor.isOver(),
// 是否可以被放置
canDrop: monitor.canDrop(),
})
)
class Dustbin extends React.Component {
static propTypes = {
canDrop: PropTypes.bool.isRequired,
isOver: PropTypes.bool.isRequired,
connectDropTarget: PropTypes.func.isRequired
}
render() {
const { canDrop, isOver, connectDropTarget } = this.props;
const isActive = canDrop && isOver;
let backgroundColor = '#222';
// 拖拽组件此时正处于 drag target 区域时,当前组件背景色变为 darkgreen
if (isActive) {
backgroundColor = 'darkgreen';
}
// 当前组件可以放置 drag source 时,背景色变为 pink
else if (canDrop) {
backgroundColor = 'darkkhaki';
}
// 使用 connectDropTarget 包裹住 DOM 节点,使其可以接收对应的 drag source 组件
// connectDropTarget 包裹住的 DOM 节点才能接收 drag source 组件
return connectDropTarget && connectDropTarget(
<div style={{ ...style, backgroundColor }}>
{isActive ? 'Release to drop' : 'Drag a box here'}
</div>
);
}
}
export default Dustbin;
Используйте DragDropContext в файле App.js
App.js
import React, { Component } from 'react';
import { DragDropContext } from 'react-dnd';
import HTMLBackend from 'react-dnd-html5-backend';
import Dustbin from './components/Dustbin';
import Box from './components/Box';
// 将 HTMLBackend 作为参数传给 DragDropContext
@DragDropContext(HTMLBackend)
class App extends Component {
render() {
return (
<div style={{ paddingLeft: 200, paddingTop: 50 }}>
<div style={{ overflow: 'hidden', clear: 'both' }}>
<Box name="Glass" />
<Box name="Banana" />
<Box name="Paper" />
</div>
<div style={{ overflow: 'hidden', clear: 'both' }}>
<Dustbin />
</div>
</div>
);
}
}
export default App;
Запустите проект, чтобы увидеть эффект
Запустите проект:
$ npm run start
Браузер автоматически откроетсяhttp://localhost:3000/
окно, вы можете работать с компонентом Box в браузере, комбинировать код проекта и просматривать эффект.
Эффект предварительного просмотра выглядит следующим образом:
6. Демонстрационный адрес этой статьи
Добро пожаловать Звезду! Спасибо!
7. Справочная ссылка
официальная документация react-dnd Перетаскивание компонентов: использование React DnD