React中使用dnd-kit修正可滚动区域拖拽位置偏移问题
解决dnd-kit拖拽元素在滚动日历容器内的位置偏移问题
你遇到的问题是因为dnd-kit计算拖拽元素的transform坐标时基于视口位置,而日历容器的横向滚动(scrollLeft)会导致拖拽元素的视觉位置和触摸/鼠标位置错位——容器向右滚动多少,拖拽元素就会偏右多少。
核心解决方案:在Draggable组件内动态抵消滚动偏移
不要直接操作DOM修改样式(会被dnd-kit的实时更新覆盖),而是基于dnd-kit返回的transform值,结合日历容器的scrollLeft调整拖拽坐标。
修改你的Draggable组件代码如下:
import { useDraggable } from '@dnd-kit/core'; import styled from "styled-components"; import { useEffect, useRef } from 'react'; const StyledDraggable = styled.div` z-index: 2; transform: ${props => props.transform}; position: ${props => props.position}; touch-action: manipulation; `; export function Draggable(props) { const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({ id: props.id, data: { type: 'draggable', droppableId: props.id, date: props.startDate } }); // 缓存日历滚动容器的引用 const calendarScrollRef = useRef(null); useEffect(() => { calendarScrollRef.current = document.querySelector("#scrollContainer"); }, []); // 计算调整后的拖拽坐标:抵消容器的横向滚动量 let adjustedX = transform?.x || 0; if (isDragging && calendarScrollRef.current) { adjustedX -= calendarScrollRef.current.scrollLeft; } const tForm = transform ? `translate3d(${adjustedX}px, ${transform.y}px, 0)` : undefined; const position = isDragging ? 'absolute' : null; return ( <StyledDraggable ref={setNodeRef} transform={tForm} position={position} {...listeners} {...attributes}> {props.children} </StyledDraggable> ); }
为什么之前的尝试失败?
你直接通过DOM修改transform样式,但dnd-kit在拖拽过程中会实时更新拖拽元素的transform属性,你的手动修改会被框架的状态更新覆盖,所以无法生效。正确的做法是在组件内部基于dnd-kit提供的transform值进行调整,让React统一管理样式。
可选优化:仅在拖拽到日历区域时生效
如果你的拖拽元素可能在非日历区域使用,可以通过useDraggable返回的over参数判断当前是否悬停在日历的Droppable区域,再应用偏移:
// 在useDraggable的返回值中解构over const { attributes, listeners, setNodeRef, transform, isDragging, over } = useDraggable(...) // 调整判断逻辑:只有悬停在日历的droppable上时才抵消偏移 if (isDragging && calendarScrollRef.current && over?.startsWith('calendar-cell-')) { adjustedX -= calendarScrollRef.current.scrollLeft; }
(这里假设你的日历单元格Droppable的id以calendar-cell-开头,根据实际情况修改判断条件)
内容的提问来源于stack exchange,提问作者dgergely
相关产品推荐
相关产品推荐

