diff --git a/src/hooks/useScrollDrag.ts b/src/hooks/useScrollDrag.ts index 36dfaab..22b14aa 100644 --- a/src/hooks/useScrollDrag.ts +++ b/src/hooks/useScrollDrag.ts @@ -38,6 +38,12 @@ export default function useScrollDrag( }); }; + // 清理拖拽状态的统一函数 + const clearDragState = () => { + mouseDownLock = false; + stopScroll(); + }; + const onMouseDown = (e: MouseEvent) => { // Skip if element set draggable if ((e.target as HTMLElement).draggable || e.button !== 0) { @@ -52,10 +58,15 @@ export default function useScrollDrag( mouseDownLock = true; } }; + const onMouseUp = () => { - mouseDownLock = false; - stopScroll(); + clearDragState(); }; + + const onDragStart = () => { + clearDragState(); + }; + const onMouseMove = (e: MouseEvent) => { if (mouseDownLock) { const mouseY = getPageXY(e, false); @@ -78,11 +89,16 @@ export default function useScrollDrag( ele.addEventListener('mousedown', onMouseDown); ele.ownerDocument.addEventListener('mouseup', onMouseUp); ele.ownerDocument.addEventListener('mousemove', onMouseMove); + + ele.ownerDocument.addEventListener('dragstart', onDragStart); + ele.ownerDocument.addEventListener('dragend', clearDragState); return () => { ele.removeEventListener('mousedown', onMouseDown); ele.ownerDocument.removeEventListener('mouseup', onMouseUp); ele.ownerDocument.removeEventListener('mousemove', onMouseMove); + ele.ownerDocument.removeEventListener('dragstart', onDragStart); + ele.ownerDocument.removeEventListener('dragend', clearDragState); stopScroll(); }; } diff --git a/tests/scroll.test.js b/tests/scroll.test.js index e3a7e04..48d03e7 100644 --- a/tests/scroll.test.js +++ b/tests/scroll.test.js @@ -731,4 +731,85 @@ describe('List.Scroll', () => { jest.useRealTimers(); }); + + it('should not scroll after drop table text', () => { + + const onScroll = jest.fn(); + // 这两个事件绑定在 document + const onDragStart = jest.fn(); + const onDragEnd = jest.fn(); + document.addEventListener('dragstart', onDragStart); + document.addEventListener('dragend', onDragEnd); + + const { container } = render( + + {({ id }) =>
  • {id}
  • } +
    , + ); + // 选择第一个可见的 fixed-item 的文本内容 + const fixedItems = container.querySelectorAll('.fixed-item'); + const targetItem = fixedItems[0]; // 使用第一个可见元素 + if (targetItem) { + const range = document.createRange(); + range.selectNodeContents(targetItem); + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + } + // 选中 fixed-item 里的文本并拖拽文本到列表底部 + const listHolder = container.querySelector('.rc-virtual-list-holder'); + if (targetItem && listHolder) { + // 创建选区,选中 fixed-item 的文本 + const range = document.createRange(); + range.selectNodeContents(targetItem); + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + + // 模拟拖拽文本 + fireEvent.dragStart(targetItem, { bubbles: true }); + + // 拖拽到列表底部 + const rect = listHolder.getBoundingClientRect(); + fireEvent.dragOver(listHolder, { + clientY: rect.bottom + 10, + bubbles: true, + }); + + // 松开鼠标 + fireEvent.drop(listHolder, { + clientY: rect.bottom + 10, + bubbles: true, + }); + + fireEvent.dragEnd(targetItem, { bubbles: true }); + } + // 检查 onScroll 没有被触发 + expect(onScroll).not.toHaveBeenCalled(); + expect(onDragStart).toHaveBeenCalled(); + expect(onDragEnd).toHaveBeenCalled(); + + // 模拟鼠标移动到列表顶部 + if (listHolder) { + const rect = listHolder.getBoundingClientRect(); + const mouseMoveEvent = new MouseEvent('mousemove', { + bubbles: true, + clientY: rect.top - 10, + }); + listHolder.dispatchEvent(mouseMoveEvent); + } + // 检查 onScroll 没有被触发 + expect(onScroll).not.toHaveBeenCalled(); + + // 清理事件监听器 + document.removeEventListener('dragstart', onDragStart); + document.removeEventListener('dragend', onDragEnd); + }); });