React Beautiful DnD嵌套列表无需跨父级拖拽 子项无法连续拖拽问题
我当前正在尝试用React Beautiful DnD实现可拖拽的容器对象列表,在这些容器内部,我又构建了一个由可拖拽元素组成的子列表。我知道这个库官方技术上不支持嵌套列表,但我已经见过很多绕过方案,而且我的使用场景比绝大多数场景都更简单,因为我完全不需要把子列表项拖到不同的父列表项之间。
目前我已经封装了一个DnDList模块,可以在两个拖拽列表中复用代码。UI效果如下,两个列表都已圈出(敏感变量名已做涂黑处理):
图片(暂不可用,审核通过后我会补充上传)
红色圈出的数字对应父列表,运行完全符合预期,我可以顺利拖拽重排这些大的div容器,没有任何问题。但蓝色圈出的子列表存在异常。
这个子列表由简单的<p>元素组成,实际可以拖拽重排,但存在一个很奇怪的问题:我无法连续拖拽这些子项。比如我点击AlphaCase这个项可以正常拖拽一次,但一旦松手放下之后,我必须先点击一次父列表内的任意区域,才能再次拖拽子列表项。每次拖拽完嵌套列表元素之后的第一次点击,都会误触发外层父元素的拖拽逻辑,变成对父列表重排。但只要我点过一次父列表内的任意内容,就可以再次正常拖拽重排子列表组件,每次嵌套列表拖拽完都会重复这个流程。(很奇怪的是,点击父列表外的区域比如Start按钮不会生效,看起来这个“重置点击”的逻辑和焦点状态有关?)
以下是我的DnDList组件代码:
<DragDropContext onDragEnd={handleDragEnd}> <Droppable droppableId={droppableId}> {(provided) => ( <ol ref={provided.innerRef} {...provided.droppableProps} className={classes.root} > {React.Children.map( children, (child: React.ReactElement | undefined, index: number) => { if (child) { const keyVal: string = getAttributeKey(child.props); return ( <Draggable key={keyVal} draggableId={keyVal} index={index}> {(provided, snapshot) => ( <li ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} > {child} </li> )} </Draggable> ); } } )} {provided.placeholder} </ol> )} </Droppable> </DragDropContext>
以下是组件的使用示例:
<DnDList handleDragEnd={handleOnDragEnd} droppableId="experiments" getAttributeKey={getAttributeKey} > {<array>.map( (experiment: string, index: number) => ( <p key={index} className={classes.experiment}> {experiment} </p> ) )} </DnDList>
getAttributeKey函数仅返回唯一字符串标识符,作为每个Draggable对象的key使用。
父列表和子列表的getAttributeKey、handleOnDragEnd逻辑基本一致:
const handleOnDragEnd = (result: DropResult) => { if (!result.destination) { return; } const newOrder: string[] = Array.from(...); const [reorderedItem] = newOrder.splice(result.source.index, 1); newOrder.splice(result.destination.index, 0, reorderedItem); onChange(...); }; const getAttributeKey = (props: any) => { return props.children; };
(我已移除所有敏感变量名,用...替代)
再次说明,我甚至不需要把子列表元素拖到父列表的其他容器里,只需要保证可以在对应的子列表内部完成拖拽即可。
内容的提问来源于stack exchange,提问作者tprebenda

