react-beautiful-dnd拖拽放置后元素位置偏移、延迟跳位问题
react-beautiful-dnd 拖拽放置后元素延迟跳位修复
问题表现:拖拽项放置到目标列表后初始渲染位置不正确,出现短暂延迟后才跳动到正确位置,元素会重新调整位置适配父容器尺寸。
效果参考:问题演示链接
问题根因
该异常由可拖拽元素多余嵌套+margin塌陷导致:
- 现有Ticket组件中,绑定
Draggable所需ref、draggableProps的是一层无样式div,实际带margin: 0 0 8px 0样式的Container是该div的子元素 - 普通块级div未触发BFC(块级格式化上下文)时,子元素的垂直margin会向外塌陷,react-beautiful-dnd拖拽过程中测量元素尺寸、计算占位符高度时,无法统计到塌陷出去的8px底部margin,导致占位高度比元素实际渲染高度小
- 拖拽刚结束时元素按测量的错误高度排列,等拖拽动画结束浏览器完成重排,margin正常生效,元素就会跳动到正确位置,这也是为什么移除margin/padding后异常会直接消失。官方示例保留列表项间距也无异常,是因为官方直接将拖拽属性绑定在了带margin的列表项根元素上,不存在嵌套导致的测量偏差。
修复方案
方案1:移除多余嵌套(推荐,和官方写法一致)
删除Draggable返回结构中多余的无样式div,直接将拖拽相关的ref、属性绑定到带样式的Container组件上,保证react-beautiful-dnd能直接测量到元素包含margin在内的真实尺寸。
修改后Ticket组件的Draggable部分代码如下:
<Draggable draggableId={id.toString()} index={index}> {(provided, snapshot) => isDeleted ? null : ( <Container ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} style={{ backgroundColor: snapshot.isDragging ? "aquamarine" : "rgba(140, 240, 255)", }} > <Title>{ticket.title}</Title> <Gradient></Gradient> <Description>{ticket.description}</Description> <button onClick={handleDelete}>Delete</button> </Container> ) } </Draggable>
方案2:保留嵌套时触发BFC规避margin塌陷
如果因业务逻辑必须保留Draggable和Container之间的嵌套div,给外层div添加触发BFC的样式,阻止子元素margin塌陷,保证测量尺寸和实际渲染尺寸一致,例如添加overflow: auto或display: flow-root:
<div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} style={{ overflow: "auto" }} > <Container style={{ backgroundColor: snapshot.isDragging ? "aquamarine" : "rgba(140, 240, 255)", }} > {/* 原有Ticket内容不变 */} </Container> </div>
其他排查提示
- 不要给绑定拖拽属性的根元素加透明边框、负margin、transform偏移这类会干扰尺寸/位置测量的属性
- 确保Droppable内的
provided.placeholder始终放在可拖拽项列表的最后,不要被其他元素遮挡或移出Droppable容器
内容的提问来源于stack exchange,提问作者Brad Bieselin
相关产品推荐
相关产品推荐

