先说下实际的场景需求,是 flex 布局下允许换行的不定长短的标签列表(类似 V2EX 首页最下面的节点导航),要求可以通过拖拽进行排序,可以从外部拖拽元素添加到指定的位置(这个“外部”可能是自己定义的 React 元素或者 Ant Design 的 Tree 组件的一个节点,不过节点这个不强求)。同时只有特定的排序或者插入的顺序是允许的,不能允许用户插入或者交换到不合法的位置(比如说所有的标签都是英文单词,然后规定是所有首字母相同的单词必须是互相挨在一起的)。同时每个标签自己还有自己的点击事件,拖拽功能不能和点击事件冲突。
调研过了几个可能比较流行的拖拽库,dnd-kit, react-beautiful-dnd, react-sortable-hoc, react-dnd 。前面三个都是封装的很好比较易用也很好看的库,但是同时存在的问题是他们要么仅支持单列列表的拖拽排序,要么可以支持多行但是仅限大小相同的网格。react-dnd 相比之下最抽象也最底层,只做了逻辑上的辅助,所有的 UI 效果要自己来。他的官方文档上有一个例子可以粗浅的实现我希望的效果,通过判断一个元素是否拖拽到另一个元素上来判断,理论上可以兼容任何布局,但是实际操作起来灵活性很差,在判定点边界的时候很容易反复判定拖拽到不同的元素上从而反复鬼畜。用起来感觉实际用户体验也远不如前面三个。
所以还有什么适合我这个需求的 React 辅助拖拽库吗?还是这个需求太奇葩了只能在 react-dnd 的基础上自己想想办法?
2
leokun 347 天前
一直用 https://interactjs.io/
api 很优美 |
3
woodytang 347 天前
需要花时间深入研究原理,没有开箱即用方案,最近在做 把网页 变成图片,截取全网页,没想到这个简单的需求,要实现完善的功能 和 稳定的服务,,都要花很多功夫
|
4
vizards 347 天前 via iPhone 1
你的要求 dnd-kit 都可以满足
1. 跨容器拖拽排序官方有 examples ,其实就是定义多个 container ,共享 draggable element ,如果需要的是从源容器复制的效果,则需要源容器内的 draggable element 在被 drop 后重新渲染(通过修改 key 或 id ),这样被拖走后他会在原地重新生成一个,或在拖拽开始/拖到可放置区域时重新生成一个新的 key 以破坏和源容器中的元素的对应关系 2. 限制特定交换顺序:真正的交换是否成功 是看渲染的结果,也就是说 dnd-kit 在拖拽完成的事件里你是否调用 arraymove 等帮助方法让列表数据改变,如果没有改变,那么拖拽就没有成功,列表顺序也不变 3. 每个标签有点击事件:可以通过 sensors 实现只监听某些地方的 pointer 事件,也可以通过监听 onPointerDown 事件来变相监听 onClick ,通过监听延迟来确定是移动还是点击(因为开启了 pointerSensor 后无法监听到 onClick ) 4. flex 不定宽排序:官网有例子,至于拖拽时可能的变形问题,可以通过动态渲染一个 drop item placeholder 实现,即保存一个自定义的 dragoverlay 数据,在元素可以被放置到某个位置但元素还处在被用户鼠标抓住时,插入此 dragoverlay 对应的元素到预测的位置,展现为一个半透明的占位,可以保证布局不变形 我目前遇到的 dnd-kit 较难做到的是多列瀑布流布局下的自由拖拽,拖拽可以实现,但是很难保证容器内不变形 |
5
nzbin 347 天前
推荐 react-dnd ,我这有个 ng-dnd ( https://github.com/ng-dnd/ng-dnd ,借鉴 react-dnd ,代码可以互转) 实现的例子 https://stackblitz.com/edit/867pxw?file=src%2Fexample%2Fdrag-drop.directive.ts ,你看看是不是你想要的效果
这个效果只是多加了个指令,然后附加到任意元素上,感觉可以借鉴一下思路 |
6
realJamespond 347 天前
https://github.com/haltu/muuri
之前找了一遍,可变列宽好像只有这个 |
8
WangLiCha OP @nzbin 其实我自己用 react-dnd 已经能做到非常接近的效果了,但是我提到那个问题还是存在,拖拽到另一个标签的边缘位置的时候还是会因为反复判定到不同的标签上从而开始疯狂闪烁……
|
9
swaggeek 347 天前
https://github.com/SortableJS/Sortable 这个可以?虽然体积有点大,但是我们用的这个
|
10
vizards 347 天前 via iPhone
@WangLiCha 实际上如果是单纯的 flex 布局(即使包含 wrap )直接 flex 排就可以了,拖拽也可以正常工作,只不过由于不定宽高,要自己处理动画变形问题
|
11
crazyweeds 347 天前
|