Commit e9dc8a33 authored by zhangwenshuai's avatar zhangwenshuai

完善拖拽列功能

parent 49fb06fc
import React, { useCallback } from 'react'; import React, { useCallback, useRef } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import s from './DragSorted.less';
const DragSorted = (props: any) => { const DragSorted = (props: any) => {
const { className, style, columnConfig, onDropFinish, onScroll } = props; const {
className, style, columnName, orderNo, onDropFinish, onScroll,
} = props;
// 长按计时器
const timer: any = useRef(null);
// 表格滚动计时器
const timerInterval: any = useRef(null);
// 表格 // 表格
const container: any = document.querySelector('#tableContainer'); const container: any = document.querySelector('#tableContainer');
// 拖拽列时的影子div // 拖拽列时的影子div
...@@ -14,115 +19,161 @@ const DragSorted = (props: any) => { ...@@ -14,115 +19,161 @@ const DragSorted = (props: any) => {
const divider: any = document.querySelector('#divider'); const divider: any = document.querySelector('#divider');
// 左侧固定列分割线 // 左侧固定列分割线
const leftFixedHandleWrap: any = document.querySelector('#leftFixedHandleWrap'); const leftFixedHandleWrap: any = document.querySelector('#leftFixedHandleWrap');
// ? 拖动目标事件 // 监听鼠标移动
// 开始拖动 const onMouseMove = useCallback((e) => {
const onDragStart = useCallback((e) => {
// 表格初始位置x点
const originLeft = container.getBoundingClientRect().x || 0;
// 拖动列矩形
const targetRect = e.target.getBoundingClientRect();
// 影子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 = e.clientX - targetRect.x;
columnCopyDiv.setAttribute('data-deta-x', detaX);
// 将拖动列信息加入拖拽事件dataTransfer中,方便后续使用
e.dataTransfer.setData('dragColumn', JSON.stringify(columnConfig));
// debugger
divider.style.left = `${targetRect.x - originLeft}px`;
dividerWrap.style.display = 'block';
}, [columnConfig.columnName]);
// 拖动中
const onDragUpdate = useCallback((e) => {
// 拖动列矩形
const targetRect = e.target.getBoundingClientRect();
const tableRect = container.getBoundingClientRect(); const tableRect = container.getBoundingClientRect();
const detaX = columnCopyDiv.getAttribute('data-deta-x'); const detaX = columnCopyDiv.getAttribute('data-deta-x');
const left = e.clientX - tableRect.x - detaX; // 所有列
console.log('left: ', left); const draggableColumns = document.querySelectorAll('.draggableColumn');
// 影子div随鼠标移动
columnCopyDiv.style.left = `${left}px`;
}, []);
// 停止拖动
const onDragEnd = useCallback((e) => {
// 停止拖动时隐藏影子div
columnCopyDiv.style.display = 'none';
dividerWrap.style.display = 'none';
console.log('stop: ');
}, []);
// ? 投放目标事件
// 在投放目标中移动
const onDragOver = useCallback((e) => {
const tableRect = container.getBoundingClientRect();
const targetRect = e.target.getBoundingClientRect();
const columnCopyDivRect = columnCopyDiv.getBoundingClientRect();
const leftFixedHandleWrapRect = leftFixedHandleWrap.getBoundingClientRect(); const leftFixedHandleWrapRect = leftFixedHandleWrap.getBoundingClientRect();
const targetWidth = targetRect.width;
const targetX = targetRect.x; const columnCopyDivRect = columnCopyDiv.getBoundingClientRect();
const columnCopyDivWidth = columnCopyDivRect.width; const columnCopyDivWidth = columnCopyDivRect.width;
const columnCopyDivX = columnCopyDivRect.x; const columnCopyDivX = columnCopyDivRect.x;
// 影子div中间点的x坐标 // 影子div中间点的x坐标
const columnCopyDivMid = columnCopyDivX + (columnCopyDivWidth / 2); const columnCopyDivMid = columnCopyDivX + columnCopyDivWidth / 2;
if (columnCopyDivMid > targetX && columnCopyDivMid < targetX + targetWidth) {
// 影子div中点在投放目标中 draggableColumns.forEach((dom) => {
divider.style.left = `${targetRect.x - tableRect.x}px`; 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') { if (typeof onScroll === 'function') {
let dir = '';
let step = 10;
// 设置鼠标超出表格左右两侧时的滚动事件
if (e.clientX > tableRect.right - 30) { if (e.clientX > tableRect.right - 30) {
onScroll('right', 100); dir = 'right';
step = 100;
} else if (e.clientX > tableRect.right - 100) { } else if (e.clientX > tableRect.right - 100) {
onScroll('right', 10); dir = 'right';
step = 10;
} else if (e.clientX < leftFixedHandleWrapRect.x + 100) { } else if (e.clientX < leftFixedHandleWrapRect.x + 100) {
onScroll('left', 10); dir = 'left';
step = 10;
} else if (e.clientX < leftFixedHandleWrapRect.x + 30) { } else if (e.clientX < leftFixedHandleWrapRect.x + 30) {
onScroll('left', 100); dir = 'left';
step = 100;
} else {
dir = '';
} }
} if (dir) {
// 需要滚动,如果已有计时器,先清除再重新设置计时器
// 元素默认是不能够投放,需在目标元素的dragover事件中取消默认事件 if (timerInterval.current) {
var event = e || window.event; clearInterval(timerInterval.current);
event.preventDefault() }
}, []); timerInterval.current = setInterval(() => {
// 在投放目标中松开鼠标 onScroll(dir, step);
const onDrop = useCallback((e) => { }, 350);
const targetRect = e.target.getBoundingClientRect(); } else {
const columnCopyDivRect = columnCopyDiv.getBoundingClientRect(); // 需要停止,清除已有计时器
const targetWidth = targetRect.width; // eslint-disable-next-line no-lonely-if
const targetX = targetRect.x; if (timerInterval.current) {
const columnCopyDivWidth = columnCopyDivRect.width; clearInterval(timerInterval.current);
const columnCopyDivX = columnCopyDivRect.x; timerInterval.current = null;
// 影子div中间点的x坐标
const columnCopyDivMid = columnCopyDivX + (columnCopyDivWidth / 2);
if (columnCopyDivMid > targetX && columnCopyDivMid < targetX + targetWidth) {
// 影子div中点在投放目标中
try {
const dragColumn = JSON.parse(e.dataTransfer.getData('dragColumn'));
const dropColumn = columnConfig;
if (typeof onDropFinish === 'function') {
onDropFinish(dragColumn, dropColumn);
} }
} catch (e) {
console.error('json解析失败')
} }
} }
}, [columnConfig.columnName]); }, []);
// 监听鼠标抬起
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 ( return (
<div <div
className={classNames(s.draggableDiv, className)} className={classNames('draggableColumn', className)}
style={style} style={style}
draggable={true} onMouseDown={onMouseDown}
onDragStart={onDragStart} onMouseUp={onMouseUp}
onDrag={onDragUpdate} data-column-name={columnName}
onDragEnd={onDragEnd} data-column-order={orderNo}
onDragOver={onDragOver}
onDrop={onDrop}
> >
{props.children} {props.children}
</div> </div>
......
...@@ -142,6 +142,7 @@ ...@@ -142,6 +142,7 @@
bottom: 0; bottom: 0;
background: rgba(0,0,0,0.3); background: rgba(0,0,0,0.3);
z-index: 5; z-index: 5;
pointer-events: none; //pointer-events: none;
display: none; display: none;
} cursor: grab;
\ No newline at end of file }
...@@ -317,9 +317,10 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -317,9 +317,10 @@ export default class AirTable extends Component<TableProps, TableState> {
questionText, questionText,
icon, icon,
requiredFlag, requiredFlag,
orderNo,
} = showColumns[columnIndex]; } = showColumns[columnIndex];
return ( return (
<DragSorted columnConfig={showColumns[columnIndex]} onDropFinish={onDragSorted} onScroll={this.onScrollHor} className={styles.headerCell} key={key} style={style}> <DragSorted columnName={columnName} orderNo={orderNo} onDropFinish={onDragSorted} onScroll={this.onScrollHor} className={styles.headerCell} key={key} style={style}>
<ResizableBox <ResizableBox
width={style.width} width={style.width}
handle={ handle={
...@@ -805,7 +806,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -805,7 +806,7 @@ export default class AirTable extends Component<TableProps, TableState> {
}} }}
/> />
</div> </div>
<div id="columnCopyDiv" className={styles.columnCopyDiv} /> <div id="columnCopyDiv" className={styles.columnCopyDiv} draggable={true} />
</div> </div>
); );
}} }}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment