拖放( D)
@cloud-ru/ds-drag-and-drop {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1} - {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1} - {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1} - {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1}.
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? Логику
(сенсоры,коллизии也
(单位:千美元)@dnd-kit, HTML5 DnD, собственные. Примитивы,как也
? ? ? ? ? ? ? ? ? ? ? ? ? ? .
DragGhost{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢.DragPreview- поверхность, которая, курсором.DropIndicator- 。 。 。 。 .DropTarget{\fn黑体\fs20\shad2\2ah82\3ah20\4ah33\fscx95\3ch592001\be1} - ... {\fn黑体\fs20\shad2\2ah82\3ah20\4ah33\fscx95\3ch592001\be1} - ... {\fn黑体\fs20\shad2\2ah82\3ah20\4ah33\fscx95\3ch592001\be1} - ...
Когда
- {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1}########################### ##########################################################################################################################################################################################################.
- {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得怎样
DropTarget) (中文(简体) ). - Порядок:а也
DropIndicator页:1 (原始内容存档于2017-10-29). qq (динамический).
Когда не нужен:
- {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1}你觉得怎么样
- у
@cloud-ru/ds-list{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢onItemsReorder- примитивы уже встроены встроены встроены.
- у
- {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1}你觉得怎样
- (原始内容存档于2019-10-21). DnD-библиотека, эти.
Анатомия
QQ (默认) static(中文(简体) )
Перенос. {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1}你觉得呢 на:смешивать也 интерфейсы.
static- соседи на месте месте исходная исходная приглушается (приглушается стоят месте месте месте месте месте месте месте месте приглушается приглушается приглушается (приглушается приглушается приглушается приглушается приглушается)DragGhostсdragging, (中文(简体) ), {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢DropIndicator) (中文(简体) ). {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1}你觉得呢 режим:длинные也.dynamic- расступаются, на, попадания, остаётся (слот, слот, слот)DragGhostсdraggingиmode='dynamic') (中文(简体) ). Линию:точку也 пустота,а也.
Режим:копия也DragPreview{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢
(单位:千美元)DropTarget)"в""обоих".
DragGhost (默认) dragging: false, (中文(简体) ), mode: static(中文(简体) )
{\fn华文仿宋\fs16\1cHD1D1D1}好. dragging включает, mode 校对:soup
static - приглушение на своём месте, dynamic - становится, сохраняя, своё
{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢.
Заменяет:обёртку也 innerRef, (中文(简体) ),
className {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢 <div>Создаёт,поэтому DropIndicator
с placement {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢.
拖放预览
Обёртка:поверхность也 любым-相去相去相去相去相去相去相去相去相去相去.
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得怎么样? {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1}你觉得呢, {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢.
投放指示器( 默认) horizontal(中文(简体) )
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得怎样? {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你还好吧 {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢.
Ориентация:
horizontal{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢.vertical{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢.
{\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1}你觉得怎样.
placement {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢 before - перед,ним, after - 额...
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢
с. Без placement {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢.
atEdge нужен:у也
{\fn黑体\fs20\shad2\2ah82\3ah20\4ah33\fscx95\3ch592001\be1}你觉得怎么样.
投放目标( 默认) active: false(中文(简体) )
Область,принимающая也. active {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢.
Рамка-признак {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢, а:отпускают也. {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢 зоны:там也, {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢.
Обводка внутри {\fn黑体\fs20\shad2\2ah82\3ah20\4ah33\fscx95\3ch592001\be1}你觉得怎样.
Установка
pnpm add @cloud-ru/ds-drag-and-drop
import {
DRAG_MODE,
DragGhost,
DragPreview,
DropIndicator,
DropTarget,
ORIENTATION,
PLACEMENT,
} from '@cloud-ru/ds-drag-and-drop'
Примеры
Поверхность
DragPreview # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ## # # # # # # # # # # # #####################################################################################################################################
import { DragPreview } from '@cloud-ru/ds-drag-and-drop';
import styles from './demo.module.scss';
export function PreviewSurface() {
return (
<DragPreview className={styles.entity}>
<div className={styles.row}>ListItem 2</div>
</DragPreview>
);
}
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢 @dnd-kit . . . . . С
N библиотекой isDragging 编号 : over{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢.
Статический
Потяните:соседи也
import { closestCenter, DndContext, DragOverlay, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
import { arrayMove, SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
import { DRAG_MODE, DragGhost, DragPreview, DropIndicator, PLACEMENT } from '@cloud-ru/ds-drag-and-drop';
import { useState } from 'react';
import styles from './demo.module.scss';
const INITIAL_ROWS = [
{ id: 'row-1', label: 'ListItem 1' },
{ id: 'row-2', label: 'ListItem 2' },
{ id: 'row-3', label: 'ListItem 3' },
{ id: 'row-4', label: 'ListItem 4' },
];
function Row({ id, label, lastIndex }: { id: string; label: string; lastIndex: number }) {
const { activeIndex, attributes, index, isDragging, listeners, overIndex, setNodeRef } = useSortable({ id });
// Статический перенос: соседи стоят на месте, поэтому трансляцию от `@dnd-kit` строке
// не применяем. Точку вставки отмечает линия на строке-цели, сторона — по тому, откуда
// пришла перетаскиваемая строка.
const showIndicator = activeIndex !== -1 && index === overIndex && index !== activeIndex;
const placement = overIndex > activeIndex ? PLACEMENT.After : PLACEMENT.Before;
return (
<DragGhost
innerRef={setNodeRef}
dragging={isDragging}
mode={DRAG_MODE.Static}
className={styles.grabbable}
{...attributes}
{...listeners}
>
<div className={styles.row}>{label}</div>
{showIndicator && (
<DropIndicator
placement={placement}
atEdge={
(index === 0 && placement === PLACEMENT.Before) || (index === lastIndex && placement === PLACEMENT.After)
}
/>
)}
</DragGhost>
);
}
export function InsertionLine() {
const [rows, setRows] = useState(INITIAL_ROWS);
const [activeId, setActiveId] = useState<string>();
// Порог в 4px: без него клик по строке уже считался бы началом переноса.
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 4 } }));
const activeRow = rows.find(row => row.id === activeId);
return (
<DndContext
// Фиксированный id: без него `@dnd-kit` нумерует свои aria-узлы счётчиком, и на
// SSR-странице разметка расходится с клиентской.
id='insertion-line'
sensors={sensors}
collisionDetection={closestCenter}
onDragStart={({ active }) => setActiveId(String(active.id))}
onDragCancel={() => setActiveId(undefined)}
onDragEnd={({ active, over }) => {
setActiveId(undefined);
if (!over || active.id === over.id) {
return;
}
setRows(rows =>
arrayMove(
rows,
rows.findIndex(row => row.id === active.id),
rows.findIndex(row => row.id === over.id),
),
);
}}
>
<SortableContext items={rows.map(row => row.id)} strategy={verticalListSortingStrategy}>
<div className={styles.list}>
{rows.map(row => (
<Row key={row.id} id={row.id} label={row.label} lastIndex={rows.length - 1} />
))}
</div>
</SortableContext>
{/* Копия за курсором: позиционирует её `DragOverlay`, поверхность даёт `DragPreview`. */}
<DragOverlay dropAnimation={null}>
{activeRow && (
<DragPreview className={styles.entity}>
<div className={styles.row}>{activeRow.label}</div>
</DragPreview>
)}
</DragOverlay>
</DndContext>
);
}
Динамический
Потяните:соседи也
import { closestCenter, DndContext, DragOverlay, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
import { arrayMove, SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { DRAG_MODE, DragGhost, DragPreview } from '@cloud-ru/ds-drag-and-drop';
import { useState } from 'react';
import styles from './demo.module.scss';
const INITIAL_ROWS = [
{ id: 'row-1', label: 'ListItem 1' },
{ id: 'row-2', label: 'ListItem 2' },
{ id: 'row-3', label: 'ListItem 3' },
{ id: 'row-4', label: 'ListItem 4' },
];
function Row({ id, label }: { id: string; label: string }) {
const { attributes, isDragging, listeners, setNodeRef, transform, transition } = useSortable({ id });
return (
<DragGhost
innerRef={setNodeRef}
dragging={isDragging}
mode={DRAG_MODE.Dynamic}
className={styles.grabbable}
// Динамический перенос: соседи расступаются трансляцией от `@dnd-kit`, а слот
// перетаскиваемой строки пустеет и сам показывает точку вставки — линия не нужна.
style={{ transform: CSS.Translate.toString(transform), transition }}
{...attributes}
{...listeners}
>
<div className={styles.row}>{label}</div>
</DragGhost>
);
}
export function DynamicGap() {
const [rows, setRows] = useState(INITIAL_ROWS);
const [activeId, setActiveId] = useState<string>();
// Порог в 4px: без него клик по строке уже считался бы началом переноса.
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 4 } }));
const activeRow = rows.find(row => row.id === activeId);
return (
<DndContext
// Фиксированный id: без него `@dnd-kit` нумерует свои aria-узлы счётчиком, и на
// SSR-странице разметка расходится с клиентской.
id='dynamic-gap'
sensors={sensors}
collisionDetection={closestCenter}
onDragStart={({ active }) => setActiveId(String(active.id))}
onDragCancel={() => setActiveId(undefined)}
onDragEnd={({ active, over }) => {
setActiveId(undefined);
if (!over || active.id === over.id) {
return;
}
setRows(rows =>
arrayMove(
rows,
rows.findIndex(row => row.id === active.id),
rows.findIndex(row => row.id === over.id),
),
);
}}
>
<SortableContext items={rows.map(row => row.id)} strategy={verticalListSortingStrategy}>
<div className={styles.list}>
{rows.map(row => (
<Row key={row.id} id={row.id} label={row.label} />
))}
</div>
</SortableContext>
<DragOverlay dropAnimation={null}>
{activeRow && (
<DragPreview className={styles.entity}>
<div className={styles.row}>{activeRow.label}</div>
</DragPreview>
)}
</DragOverlay>
</DndContext>
);
}
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢
Перетащите:рамку也
import {
DndContext,
DragOverlay,
PointerSensor,
useDraggable,
useDroppable,
useSensor,
useSensors,
} from '@dnd-kit/core';
import { DragGhost, DragPreview, DropTarget } from '@cloud-ru/ds-drag-and-drop';
import { useState } from 'react';
import styles from './demo.module.scss';
const ZONES = [
{ id: 'zone-1', label: 'Зона 1' },
{ id: 'zone-2', label: 'Зона 2' },
];
const INITIAL_ITEMS = [
{ id: 'item-1', label: 'ListItem 1', zoneId: 'zone-1' },
{ id: 'item-2', label: 'ListItem 2', zoneId: 'zone-1' },
{ id: 'item-3', label: 'ListItem 3', zoneId: 'zone-2' },
];
type Item = (typeof INITIAL_ITEMS)[number];
function Row({ id, label }: Pick<Item, 'id' | 'label'>) {
const { attributes, isDragging, listeners, setNodeRef } = useDraggable({ id });
return (
<DragGhost innerRef={setNodeRef} dragging={isDragging} className={styles.grabbable} {...attributes} {...listeners}>
<div className={styles.row}>{label}</div>
</DragGhost>
);
}
function Zone({ id, label, items, sourceZoneId }: { id: string; label: string; items: Item[]; sourceZoneId?: string }) {
const { isOver, setNodeRef } = useDroppable({ id });
// Рамка — признак переноса между зонами: своя зона её не получает.
const active = isOver && sourceZoneId !== undefined && sourceZoneId !== id;
return (
<DropTarget innerRef={setNodeRef} active={active} className={styles.zone}>
<div className={styles.zoneLabel}>{label}</div>
{items.map(item => (
<Row key={item.id} id={item.id} label={item.label} />
))}
</DropTarget>
);
}
export function ActiveZone() {
const [items, setItems] = useState(INITIAL_ITEMS);
const [activeId, setActiveId] = useState<string>();
// Порог в 4px: без него клик по строке уже считался бы началом переноса.
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 4 } }));
const activeItem = items.find(item => item.id === activeId);
return (
<DndContext
// Фиксированный id: без него `@dnd-kit` нумерует свои aria-узлы счётчиком, и на
// SSR-странице разметка расходится с клиентской.
id='active-zone'
sensors={sensors}
onDragStart={({ active }) => setActiveId(String(active.id))}
onDragCancel={() => setActiveId(undefined)}
onDragEnd={({ active, over }) => {
setActiveId(undefined);
if (!over) {
return;
}
setItems(items => items.map(item => (item.id === active.id ? { ...item, zoneId: String(over.id) } : item)));
}}
>
<div className={styles.zones}>
{ZONES.map(zone => (
<Zone
key={zone.id}
id={zone.id}
label={zone.label}
items={items.filter(item => item.zoneId === zone.id)}
sourceZoneId={activeItem?.zoneId}
/>
))}
</div>
<DragOverlay dropAnimation={null}>
{activeItem && (
<DragPreview className={styles.entity}>
<div className={styles.row}>{activeItem.label}</div>
</DragPreview>
)}
</DragOverlay>
</DndContext>
);
}
道具
拖曳幽灵
拖曳Ghost 选项
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
children | ReactNode | —— 说 | Сущность,остающаяся也. |
className | string | —— 说 | 支助科 |
data-test-id | string | —— 说 | |
dragging | boolean | false | {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? По:假 |
innerRef | Ref<HTMLDivElement> | —— 说 | 校对:Soup. |
mode | "dynamic" | "static" | static | 校对:Soup static - соседи на месте приглушается приглушается показывает DropIndicator· ; dynamic - расступаются сразу сразу слот {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1}你觉得呢? :静态 |
相关类型
DragMode=:"dynamic"|"static"
拖放预览
拖放预览程序
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
children | ReactNode | —— 说 | Перетаскиваемая:строка也. |
className | string | —— 说 | 支助科 |
data-test-id | string | —— 说 | |
innerRef | Ref<HTMLDivElement> | —— 说 | 参考文献: |
投递指示器
投放指标
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
atEdge | boolean | false | {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢 {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? Работает вместе placement。 。 。 . По:假 |
className | string | —— 说 | 支助科 |
data-test-id | string | —— 说 | |
innerRef | Ref<HTMLDivElement> | —— 说 | 参考文献: |
orientation | "horizontal" | "vertical" | horizontal | Ориентация:水平-между,垂直-между. QQ: 横向 |
placement | "after" | "before" | —— 说 | {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # потребитель. Требует position {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你觉得呢. |
相关类型
-
Orientation=:"horizontal"|"vertical" -
Placement=:"after"|"before"
投放目标
投放目标
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
active | boolean | false | {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得怎么样? По:假 |
children | ReactNode | —— 说 | Содержимое |
className | string | —— 说 | 支助科 |
data-test-id | string | —— 说 | |
innerRef | Ref<HTMLDivElement> | —— 说 | D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. . D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. D. . D. D. D. . . D. D. D. . D. . . D. D. . D. D. . D. D. . . D. D. . D. D. . . D. . . . . D. . |
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢 <div>, (中文(简体) ), data-test-id 阿丽亚..
и innerRef (原始内容存档于2019-10-21) (英语). DnD.
Смотри
- 列表 {\fn黑体\fs20\shad2\2ah82\3ah20\4ah33\fscx95\3ch592001\be1}你觉得呢.