概述

1. 可选组件

1.1 组件总览

antDesign推荐的 4 种可拖动组件

名称startUnpacked Size说明
react-beautiful-dnd24.4K1.39 MB
react-dnd16.2K673 kB
react-sortable-hoc9.5K798 kBProComponents 的 Table 例子用到
dnd-kit2.2K732 kB

1.2 参考文档

2. AntDesign 例子

antDesigndnd的例子给了很多拖动的例子,用了不同的组件,这点很烦人。

2.1 upload

上传列表拖拽排序使用 itemRender ,我们可以集成 react-dnd 来实现对上传列表拖拽排序。

2.2 table

可以拖动table中的行,antDesign给出了两种实现方式

以上两个实现方式的源代码,可以在例子文档中获得。

3. 组件选型

3.1 主选方案

react-dnd

名称推荐程度说明
react-beautiful-dnd☆☆☆代码比较复杂,放弃
react-dnd☆☆☆☆☆侵入性小,代码简洁
react-sortable-hoc☆☆功能单一,只能作为排序,但是使用起来简单
dnd-kit用的人不多,放弃

3.2 备选方案

react-beautiful-dnd 排名第一的拖拽组件,所以要研究以下。

安装与使用

# yarn
tyarn add react-beautiful-dnd
tyarn add array-move
import { DragDropContext } from 'react-beautiful-dnd';
import arrayMove from 'array-move';

安装 types 依赖

tyarn add @types/react-beautiful-dnd -D

react-beautiful-dnd-multi-list-typescript-example

删除依赖

tyarn remove react-beautiful-dnd
tyarn remove @types/react-beautiful-dnd -D

例子代码,这个代码要保留下来,因为里面记录了具体的使用方法。

import React from 'react';
// 拖拽组件相关的引用
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
import type {
DraggingStyle,
NotDraggingStyle,
DropResult,
DroppableProvided,
DroppableStateSnapshot,
} from 'react-beautiful-dnd/index';
import type { CSSProperties } from 'react';
const grid = 8;
/**
* 水平样式
* @param isDragging
* @param draggableStyle
* @returns
*/
const getItemStyle = (
isDragging: boolean,
draggableStyle: DraggingStyle | NotDraggingStyle | undefined,
): CSSProperties | undefined => ({
// 基本的设置
userSelect: 'none',
padding: grid * 2,
margin: `0 ${grid}px 0 0`,
// 拖动时改变背景颜色
background: isDragging ? 'lightgreen' : 'grey',
// 可拖动时的样式
...draggableStyle,
});
/**
* 得到列表的样式
* @param isDraggingOver
* @returns
*/
const getListStyle = (isDraggingOver: boolean) => ({
background: isDraggingOver ? 'lightblue' : 'lightgrey',
display: 'flex',
padding: grid,
overflow: 'auto',
});
interface ItemType {
id: string;
content: string;
}
export default () => {
const [items, SetItems] = React.useState<ItemType[]>([
{ id: 'item-0', content: 'hello' },
{ id: 'item-1', content: 'I' },
{ id: 'item-2', content: 'am' },
{ id: 'item-3', content: '卡' },
{ id: 'item-4', content: '特' },
{ id: 'item-5', content: '洛' },
]);
// a little function to help us with reordering the result
/**
* 重新排序的函数
* @param list 要排序的数组
* @param startIndex
* @param endIndex
* @returns
*/
const reOrder = (list: ItemType[], startIndex: number, endIndex: number) => {
const result = Array.from(list);
// 得到要删除的元素
const [removed] = result.splice(startIndex, 1);
// 将删除的元素添加到 endIndex
result.splice(endIndex, 0, removed);
return result;
};
/**
* 拖动结束事件
* @param result
*/
const onDragEnd = (result: DropResult): void => {
// 拖动到列表以外了
if (!result.destination) {
return;
}
console.log(result);
const newItems = reOrder(
items,
result.source.index,
result.destination.index,
);
SetItems(newItems);
};
return (
<div className="App">
<DragDropContext onDragEnd={onDragEnd}>
{/* 可以落下的区域 */}
<Droppable droppableId="imgList" direction="horizontal">
{(provided: DroppableProvided, snapshot: DroppableStateSnapshot) => {
console.log(provided, snapshot);
return (
<div
ref={provided.innerRef}
style={getListStyle(snapshot.isDraggingOver)}
{...provided.droppableProps}
>
{items.map((item, index) => (
/** 可拖动组件 */
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={getItemStyle(
snapshot.isDragging,
provided.draggableProps.style,
)}
>
{item.content}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
);
}}
</Droppable>
</DragDropContext>
</div>
);
};