import React, { useCallback, useRef } from 'react'; import classNames from 'classnames'; import s from './DragSorted.less'; const DragSorted = (props: any) => { const { className, columnName, orderNo, onDropFinish, onScroll, canDrag, tableId } = props; // 长按计时器 const timer: any = useRef(null); // 表格滚动计时器 const timerInterval: any = useRef(null); // 表格 const container: any = document.querySelector(`#apolloTable_${tableId}`); // 拖拽列时的影子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 rightFixedHandleWrap: any = document.querySelector('#rightFixedHandleWrap'); // 监听鼠标移动 const onMouseMove = useCallback((e) => { const tableRect = container.getBoundingClientRect(); const detaX = columnCopyDiv.getAttribute('data-deta-x'); // 所有列 const draggableColumns = document.querySelectorAll('.draggableColumn'); const leftFixedHandleWrapRectX = (leftFixedHandleWrap && leftFixedHandleWrap.getBoundingClientRect().x) || 0; const rightFixedHandleWrapRectX = (rightFixedHandleWrap && rightFixedHandleWrap.getBoundingClientRect().x) || tableRect.right; const columnCopyDivRect = columnCopyDiv.getBoundingClientRect(); const columnCopyDivWidth = columnCopyDivRect.width; const columnCopyDivX = columnCopyDivRect.x; // 影子div中间点的x坐标 const columnCopyDivMid = columnCopyDivX + columnCopyDivWidth / 2; const left = e.clientX - tableRect.x - Number(detaX); // 影子div随鼠标移动 // 鼠标在左侧固定列与右侧固定列之间有效 if (e.clientX > leftFixedHandleWrapRectX && e.clientX < rightFixedHandleWrapRectX) { columnCopyDiv.style.left = `${left}px`; } draggableColumns.forEach((dom) => { const domRect = dom.getBoundingClientRect(); // 当前节点在左侧固定列与右侧固定列之间有效 if ( domRect.x > leftFixedHandleWrapRectX && domRect.x < rightFixedHandleWrapRectX && 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); } }); if (typeof onScroll === 'function') { let dir = ''; let step = 10; // 设置鼠标超出表格左右固定列两侧时的滚动事件 if (columnCopyDivX + columnCopyDivWidth > rightFixedHandleWrapRectX - 50) { dir = 'right'; step = 100; } else if (columnCopyDivX + columnCopyDivWidth > rightFixedHandleWrapRectX - 100) { dir = 'right'; step = 30; } else if (columnCopyDivX < leftFixedHandleWrapRectX + 100) { dir = 'left'; step = 30; } else if (columnCopyDivX < leftFixedHandleWrapRectX + 50) { 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) }, ); } }, [onDropFinish]); // 监听鼠标按下 const onMouseDown = useCallback( (e) => { // 没有拖拽回调,默认不支持拖拽事件 if (!canDrag) { return; } // 不是左键点击不作处理 if (e.button !== 0) { return; } // 表格初始位置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 (