You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 21:32:41