如何基于 antd Upload 组件的图片墙实现拖拽排序

前言:最近遇到一个需求,需要图片上传之后,可以拖拽图片改变图片展示的顺序。我经过搜索发现目前 antdUpload 组件并未支持拖拽排序功能,网上也没发现可以借鉴的例子,于是我自己基于 react-sortable-hoc 实现了这个效果,如有需要可以参考。


最终效果及源码

预览

技术选型

市面上可以实现拖拽排序的库有很多,比如 SortableJS、react-dnd 、react-beautiful-dnd 、react-sortable-hoc等。上面列出来的几个库我都大致了解了一遍,下面我将介绍自己是如何选择这几个库的。

SortableJS

首先考虑的是 SortableJS,它足够轻量级,而且功能齐全,但是在 React 中使用起来并不是太方便,而且它的配置项写起来实在不太符合 React 的思维,PASS。

react-dnd 和 react-beautiful-dnd

这两个库是专门为 react 使用者写的库,在 react中用起来很顺畅。但是 react-dnd 拖拽的动画效果一般,react-beautiful-dnd 的动画效果和细节非常完美。所以我在最开始选用的是 react-beautiful-dnd,在源码中也能发现实际上我还基于 react-beautiful-dnd 实现了一个版本 PicturesWall 组件。但是后来发现,这两个库其实都只支持同一个方向上的拖拽,如果是多行的图片墙,效果就非常不好,所以最终我选择了下面的 react-sortable-hoc。

react-sortable-hoc

这就是我最终的选择,专门为 React 使用者开发的拖拽排序库,支持多行拖拽排序,动画效果也还可以。当然这也不是完美的方案,因为在实际体验中,react-sortable-hoc 的一些动画细节和操作细节并没有优化的特别好,但是:

如何基于 antd Upload 组件的图片墙实现拖拽排序_第1张图片
又不是不能用.jpg

使用 react-sortable-hoc 实现拖拽排序

完整代码详见 PicturesGrid 组件。下面会列一些核心代码:

  • SortableItem:
const SortableItem = SortableElement((params: SortableItemParams) => (
  
));
  • SortableList
const SortableList = SortableContainer((params: SortableListParams) => {
  return (
    
{params.items.map((item, index) => ( ))} {params.props.children}
); });
  • PicturesGrid 核心代码
<>
  
   setPreviewImage('')}
    bodyStyle={{ padding: 0 }}
  >
    
  


遇到的问题和解决方案

图片墙上的按钮无法点击

在 antd 的 Upload 组件中,图片墙上会有「预览」、「删除」等按钮,但是在 react-sortable-hoc 的逻辑中,只要我点击了图片,就会触发图片的拖拽函数,无法触发图片上的各种按钮,所以需要在 SortableList上重新设置一下 distance 属性,设置成 1 即可。


该属性的含义在官网是这样介绍的:

If you'd like elements to only become sortable after being dragged a certain number of pixels. Cannot be used in conjunction with the pressDelay prop.
(如果您希望元素仅在拖动一定数量的像素后才可排序。不能与pressDelay道具一起使用。默认为 0

所以设置 distance1,就可以达成当我们点击图片按钮不触发拖拽的效果

换行问题

如何基于 antd Upload 组件的图片墙实现拖拽排序_第2张图片

如上图,从第二行拖拽至第一行,第一行的内容会超出容器,我搜到了这个 issue,通过其中的回复:

Because my container wasn't scrollable, it bubbled up to grab the width of the window. I added overflow: auto to my container and the issue was solved. …… …… Which element are you adding overflow: auto to? It should be the first parent element of the sortable elements。
(因为我的容器不可滚动,所以它冒泡使得超出了窗口的宽度。我为我的容器添加了overflow: auto,得以解决问题。您向哪个元素添加的overflow: auto?应该向可排序元素的第一个父元素添加这个属性。)

向可排序元素的第一个父元素添加这个属性添加了 overflow: auto,解决了问题。

无法上传

当我一开始完成了 PicturesGrid 组件的开发,测试发现:无法上传图片,每次发起上传图片的请求,该请求的状态会立刻变为 canceled。经过搜索,发现下面这种情况会导致请求canceled

The DOM element that caused the request to be made got deleted (i.e. an IMG is being loaded, but before the load happened, you deleted the IMG node)。
(导致发出请求的DOM元素被删除(即,正在加载IMG,但是在加载之前,您已删除IMG节点))

在通过审查元素,终于找到了原因:当图片列表发生变化,整个sortable容器被删除并重新渲染,导致请求失效。解决方案是:需要将 SortableItemSortableList 写在 React.FC 外面,每次组件内部 state 发生变化,不会重新执行 SortableContainerSortableElement方法,就可以让 可排序容器里面的元素自动只更新需要改变的 DOM 元素,而不会整个删除并重新渲染了。

(完)

你可能感兴趣的:(如何基于 antd Upload 组件的图片墙实现拖拽排序)