import React, { useCallback, useRef } from 'react'; import classNames from 'classnames'; const DragSorted = (props: any) => { const { className, style, columnName, orderNo, onDropFinish, onScroll, } = props; // 长按计时器 const timer: any = useRef(null); // 表格滚动计时器 const timerInterval: any = useRef(null); // 表格 const container: any = document.querySelector('#tableContainer'); // 拖拽列时的影子div const columnCopyDiv: any = document.querySelector('#columnCopyDiv'); // 分割线wrap const dividerWrap: any = document.querySelector('#dividerWrap'); // 分割线 const divider: any = document.querySelector('#divider'); // 左侧固定列分割线 const leftFixedHandleWrap: any = document.querySelector('#leftFixedHandleWrap'); // 监听鼠标移动 const onMouseMove = useCallback((e) => { const tableRect = container.getBoundingClientRect(); const detaX = columnCopyDiv.getAttribute('data-deta-x'); // 所有列 const draggableColumns = document.querySelectorAll('.draggableColumn'); const leftFixedHandleWrapRect = leftFixedHandleWrap.getBoundingClientRect(); const columnCopyDivRect = columnCopyDiv.getBoundingClientRect(); const columnCopyDivWidth = columnCopyDivRect.width; const columnCopyDivX = columnCopyDivRect.x; // 影子div中间点的x坐标 const columnCopyDivMid = columnCopyDivX + columnCopyDivWidth / 2; draggableColumns.forEach((dom) => { const domRect = dom.getBoundingClientRect(); if (columnCopyDivMid > domRect.x && columnCopyDivMid < domRect.x + domRect.width) { // 影子div中点在投放目标中 divider.style.left = `${domRect.x - tableRect.x}px`; // 收集投放目标的信息 const dropColumn = dom.getAttribute('data-column-name') || ''; const dropColumnOrder = dom.getAttribute('data-column-order') || ''; divider.setAttribute('data-drop-column', dropColumn); divider.setAttribute('data-drop-order', dropColumnOrder); } }); const left = e.clientX - tableRect.x - Number(detaX); // 影子div随鼠标移动 columnCopyDiv.style.left = `${left}px`; if (typeof onScroll === 'function') { let dir = ''; let step = 10; // 设置鼠标超出表格左右两侧时的滚动事件 if (e.clientX > tableRect.right - 30) { dir = 'right'; step = 100; } else if (e.clientX > tableRect.right - 100) { dir = 'right'; step = 10; } else if (e.clientX < leftFixedHandleWrapRect.x + 100) { dir = 'left'; step = 10; } else if (e.clientX < leftFixedHandleWrapRect.x + 30) { dir = 'left'; step = 100; } else { dir = ''; } if (dir) { // 需要滚动,如果已有计时器,先清除再重新设置计时器 if (timerInterval.current) { clearInterval(timerInterval.current); } timerInterval.current = setInterval(() => { onScroll(dir, step); }, 350); } else { // 需要停止,清除已有计时器 // eslint-disable-next-line no-lonely-if if (timerInterval.current) { clearInterval(timerInterval.current); timerInterval.current = null; } } } }, []); // 监听鼠标抬起 const onMouseUp = useCallback(() => { // 清空计时器 if (timer.current) { clearTimeout(timer.current); timer.current = null; } if (timerInterval.current) { clearInterval(timerInterval.current); timerInterval.current = null; } // 移除全局事件 document.body.removeEventListener('mousemove', onMouseMove, false); document.body.removeEventListener('mouseup', onMouseUp, false); // 停止拖动时隐藏影子div columnCopyDiv.style.display = 'none'; dividerWrap.style.display = 'none'; // 获取分割线上挂载的拖动列和投放列信息 const dragColumn = divider.getAttribute('data-drag-column'); const dragColumnOrder = divider.getAttribute('data-drag-order'); const dropColumn = divider.getAttribute('data-drop-column'); const dropColumnOrder = divider.getAttribute('data-drop-order'); // 没有列信息 if (!dragColumn || !dropColumn) { return; } // 没有拖动 if (Number(dropColumnOrder) === Number(dragColumnOrder)) { return; } // 拖动没有产生移动 if (Number(dropColumnOrder) - Number(dragColumnOrder) === 1) { return; } // 拖动回调 if (typeof onDropFinish === 'function') { onDropFinish( { columnName: dragColumn, orderNo: Number(dragColumnOrder) }, { columnName: dropColumn, orderNo: Number(dropColumnOrder) }, ); } }, []); // 监听鼠标按下 const onMouseDown = useCallback( (e) => { // 表格初始位置x点 const originLeft = container.getBoundingClientRect().x || 0; // 拖动列矩形 const targetRect = e.currentTarget.getBoundingClientRect(); const curX = e.clientX; // 500ms长按事件,表示想要拖拽 timer.current = setTimeout(() => { // 影子div显示 columnCopyDiv.style.display = 'block'; // 影子div初始x位置=拖动列x点-表格x点 columnCopyDiv.style.left = `${targetRect.x - originLeft}px`; // 影子div宽度=拖动列宽度 columnCopyDiv.style.width = `${targetRect.width}px`; // 鼠标x点与拖动列x点之间的距离(记录下来方便后续使用) const detaX = curX - targetRect.x; columnCopyDiv.setAttribute('data-deta-x', String(detaX)); // 分割线初始位置为当前列 divider.style.left = `${targetRect.x - originLeft}px`; dividerWrap.style.display = 'block'; // 给分割线设置拖动列信息,移除投放列信息 divider.setAttribute('data-drag-column', columnName); divider.setAttribute('data-drag-order', orderNo); divider.removeAttribute('data-drop-column'); divider.removeAttribute('data-drop-order'); // 全局添加监听鼠标移动和松开事件 document.body.addEventListener('mousemove', onMouseMove, false); document.body.addEventListener('mouseup', onMouseUp, false); }, 500); // 阻止默认行为 e.preventDefault(); }, [columnName, orderNo], ); return (