Commit 459f426a authored by zhangwenshuai's avatar zhangwenshuai

增加右侧拖拽

parent b60f523c
...@@ -19,23 +19,36 @@ const DragSorted = (props: any) => { ...@@ -19,23 +19,36 @@ 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 rightFixedHandleWrap: any = document.querySelector('#rightFixedHandleWrap');
// 监听鼠标移动 // 监听鼠标移动
const onMouseMove = useCallback((e) => { const onMouseMove = useCallback((e) => {
const tableRect = container.getBoundingClientRect(); const tableRect = container.getBoundingClientRect();
const detaX = columnCopyDiv.getAttribute('data-deta-x'); const detaX = columnCopyDiv.getAttribute('data-deta-x');
// 所有列 // 所有列
const draggableColumns = document.querySelectorAll('.draggableColumn'); const draggableColumns = document.querySelectorAll('.draggableColumn');
const leftFixedHandleWrapRect = leftFixedHandleWrap.getBoundingClientRect(); const leftFixedHandleWrapRectX = (leftFixedHandleWrap && leftFixedHandleWrap.getBoundingClientRect().x) || 0;
const rightFixedHandleWrapRectX = (rightFixedHandleWrap && rightFixedHandleWrap.getBoundingClientRect().x) || tableRect.right;
const columnCopyDivRect = columnCopyDiv.getBoundingClientRect(); 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;
const left = e.clientX - tableRect.x - Number(detaX);
// 影子div随鼠标移动
// 鼠标在左侧固定列与右侧固定列之间有效
if (e.clientX > leftFixedHandleWrapRectX && e.clientX < rightFixedHandleWrapRectX) {
columnCopyDiv.style.left = `${left}px`;
}
draggableColumns.forEach((dom) => { draggableColumns.forEach((dom) => {
const domRect = dom.getBoundingClientRect(); const domRect = dom.getBoundingClientRect();
if (columnCopyDivMid > domRect.x && columnCopyDivMid < domRect.x + domRect.width) { // 当前节点在左侧固定列与右侧固定列之间有效
if (
domRect.x > leftFixedHandleWrapRectX
&& domRect.x < rightFixedHandleWrapRectX
&& columnCopyDivMid > domRect.x
&& columnCopyDivMid < domRect.x + domRect.width
) {
// 影子div中点在投放目标中 // 影子div中点在投放目标中
divider.style.left = `${domRect.x - tableRect.x}px`; divider.style.left = `${domRect.x - tableRect.x}px`;
// 收集投放目标的信息 // 收集投放目标的信息
...@@ -46,24 +59,20 @@ const DragSorted = (props: any) => { ...@@ -46,24 +59,20 @@ const DragSorted = (props: any) => {
} }
}); });
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 dir = '';
let step = 10; let step = 10;
// 设置鼠标超出表格左右两侧时的滚动事件 // 设置鼠标超出表格左右固定列两侧时的滚动事件
if (e.clientX > tableRect.right - 30) { if (columnCopyDivX + columnCopyDivWidth > rightFixedHandleWrapRectX - 50) {
dir = 'right'; dir = 'right';
step = 100; step = 100;
} else if (e.clientX > tableRect.right - 100) { } else if (columnCopyDivX + columnCopyDivWidth > rightFixedHandleWrapRectX - 100) {
dir = 'right'; dir = 'right';
step = 10; step = 30;
} else if (e.clientX < leftFixedHandleWrapRect.x + 100) { } else if (columnCopyDivX < leftFixedHandleWrapRectX + 100) {
dir = 'left'; dir = 'left';
step = 10; step = 30;
} else if (e.clientX < leftFixedHandleWrapRect.x + 30) { } else if (columnCopyDivX < leftFixedHandleWrapRectX + 50) {
dir = 'left'; dir = 'left';
step = 100; step = 100;
} else { } else {
......
import React from 'react';
import { ResizableBox } from 'react-resizable';
import styles from './DragFixed.less';
const DragFixed = (props: any) => {
const {
initLeft,
initTop,
onResizeStart,
tableWidth,
showColumns,
columnWidth,
columns,
onResizeStop,
scrollbarWidth,
} = props;
// 表格
const container: any = document.querySelector('#tableContainer');
// 滑块wrap
const handleWrap: any = document.querySelector('#rightFixedHandleWrap');
// 滑块
const handle: any = document.querySelector('#rightFixedHandle');
// 分割线wrap
const dividerWrap: any = document.querySelector('#dividerWrap');
// 分割线
const divider: any = document.querySelector('#divider');
const onMouseEnterWrap = (e: any) => {
// 滑块wrap添加hovered样式
handleWrap.classList.add(styles.hovered);
// 滑块初始化位置,显示
handle.style.top = `${e.clientY}px`;
handle.style.opacity = 1;
};
const onMouseMoveWrap = (e: any) => {
// 滑块位置跟随鼠标上下移动
handle.style.top = `${e.clientY}px`;
};
const onMouseLeaveWrap = () => {
// 滑块wrap移除hovered样式
handleWrap.classList.remove(styles.hovered);
// 滑块隐藏
handle.style.opacity = 0;
};
const onResizeStartHandle = (e: any) => {
if (typeof onResizeStart === 'function') {
onResizeStart();
}
const originLeft = container.getBoundingClientRect().x || 0;
handleWrap.style.top = 0;
handleWrap.style.left = `${e.x - originLeft}px`;
};
const onResizeHandle = (e: any) => {
const containerRect: any = container.getBoundingClientRect();
let inTableRight = containerRect.right - e.x;
// left不能超过表格一半宽度
if (inTableRight > tableWidth / 2) {
inTableRight = tableWidth / 2;
}
let fixedWidth = 0;
let index = 0;
// 计算固定列宽度及索引
for (let i = showColumns.length - 1; i >= 0; i--) {
fixedWidth += showColumns[i].width || columnWidth;
if (fixedWidth > inTableRight) {
index = i;
break;
}
}
let rightHandleLeft = fixedWidth - (showColumns[index].width || columnWidth);
// if (inTableRight > fixedWidth - (showColumns[index].width || columnWidth) / 2) {
// // left位于当前列中间偏右
// rightHandleLeft = fixedWidth;
// } else {
// // left位于当前列中间偏左
// rightHandleLeft = fixedWidth - (showColumns[index].width || columnWidth);
// }
// 拖动时显示分割线
dividerWrap.style.display = 'block';
// 分割线取列的边侧位置
divider.style.left = `${containerRect.width - scrollbarWidth - rightHandleLeft}px`;
// 拖动线取鼠标位置
handleWrap.style.left = `${containerRect.width - scrollbarWidth - inTableRight}px`;
// 滑动过程中滑块始终显示
// 滑块wrap添加hovered样式
handleWrap.classList.add(styles.hovered);
// 滑块初始化位置,显示
handle.style.opacity = 1;
};
const onResizeStopHandle = () => {
// 当前固定列宽度为分割线的left
const fixedWidth: string = divider.style.left;
// 样式转数值
const fixedWidthNum: string = fixedWidth.slice(0, -2);
// 分隔线wrap隐藏
dividerWrap.style.display = 'none';
// 滑块wrap移除hovered样式
handleWrap.classList.remove(styles.hovered);
handleWrap.style.top = `${initTop}px`;
handleWrap.style.left = fixedWidth;
// 滑块隐藏
handle.style.opacity = 0;
let leftFixedWidth = 0;
const fixedCol: any = {};
// 计算获取固定列
for (let i = showColumns.length - 1; i >= 0; i--) {
leftFixedWidth += showColumns[i].width || columnWidth;
if (leftFixedWidth <= tableWidth + scrollbarWidth - Number(fixedWidthNum)) {
fixedCol[showColumns[i].columnName] = 1;
} else {
break;
}
}
const newColumns: any = [];
// 为固定列增加fixed属性
columns.map((item: any) => {
if (fixedCol[item.columnName] === 1) {
item.fixed = 'right';
} else {
if (item.fixed === 'right') {
item.fixed = '';
}
}
newColumns.push(item);
});
if (typeof onResizeStop === 'function') {
onResizeStop({ columns: newColumns });
}
};
return (
<div
id="rightFixedHandleWrap"
className={styles.leftFixedHandleWrap}
style={{
left: `${initLeft}px`,
top: `${initTop}px`,
}}
onMouseEnter={onMouseEnterWrap}
onMouseMove={onMouseMoveWrap}
onMouseLeave={onMouseLeaveWrap}
>
<ResizableBox
handle={
<span
id="rightFixedHandle"
className={styles.leftFixedHandle}
onClick={(e) => {
e.stopPropagation();
}}
/>
}
onResizeStart={onResizeStartHandle}
onResize={onResizeHandle}
onResizeStop={onResizeStopHandle}
draggableOpts={{ enableUserSelectHack: false }}
/>
</div>
);
};
export default DragFixed;
...@@ -141,7 +141,7 @@ ...@@ -141,7 +141,7 @@
top: 0; top: 0;
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; cursor: grab;
......
...@@ -11,6 +11,7 @@ import { TableProps, TableState, ColumnProps, RowProps } from './interface'; ...@@ -11,6 +11,7 @@ import { TableProps, TableState, ColumnProps, RowProps } from './interface';
import Column from './Column'; import Column from './Column';
import Cell from './Cell'; import Cell from './Cell';
import LeftDragFixed from './DragFixed'; import LeftDragFixed from './DragFixed';
import RightDragFixed from './RightDragFixed';
import DragSorted from './DragSorted'; import DragSorted from './DragSorted';
import { getMergeClassName, getMergeStyle } from '../utils/utils'; import { getMergeClassName, getMergeStyle } from '../utils/utils';
import { Consumer } from './context'; import { Consumer } from './context';
...@@ -266,8 +267,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -266,8 +267,7 @@ export default class AirTable extends Component<TableProps, TableState> {
// 拖拽自定义固定列前置动作 // 拖拽自定义固定列前置动作
onResizeStartLeftDragFixed = () => { onResizeStartLeftDragFixed = () => {
// 拖动开始,将表格滚动回最左端 // 拖动开始,将表格滚动回最左端
if (this.grid3 && this.grid4) { if (this.grid4) {
this.grid3.scrollToPosition({ scrollLeft: 0 });
this.grid4.scrollToPosition({ scrollLeft: 0 }); this.grid4.scrollToPosition({ scrollLeft: 0 });
} }
}; };
...@@ -283,24 +283,33 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -283,24 +283,33 @@ export default class AirTable extends Component<TableProps, TableState> {
}, },
); );
}; };
// 拖拽自定义固定列前置动作
onResizeStartRightDragFixed = () => {
// 拖动开始,将表格滚动回最右端
const { columns } = this.state;
const showColumns = this.memoizeColumns(columns);
if (this.grid4) {
this.grid4.scrollToCell({ columnIndex: showColumns.length - 1 });
}
};
onScrollHor = (direction: string, step: number) => { onScrollHor = (direction: string, step: number) => {
// 拖动超过视图范围,将表格左右滚动 // 拖动超过视图范围,将表格左右滚动
if (this.grid4) { if (this.grid4) {
if (direction === 'right') { if (direction === 'right') {
if (this.grid4.state.scrollLeft >= this.grid4.getTotalColumnsWidth() - this.state.tableWidth - 100) { if (this.grid4.state.scrollLeft >= this.grid4.getTotalColumnsWidth() - this.state.tableWidth - 100) {
console.log('已经到最右侧了') console.log('已经到最右侧了');
return; return;
} }
this.grid4.scrollToPosition({ scrollLeft: this.grid4.state.scrollLeft + step }); this.grid4.scrollToPosition({ scrollLeft: this.grid4.state.scrollLeft + step });
} else { } else {
if (this.grid4.state.scrollLeft <= 0) { if (this.grid4.state.scrollLeft <= 0) {
console.log('已经到最左侧了') console.log('已经到最左侧了');
return; return;
} }
this.grid4.scrollToPosition({ scrollLeft: this.grid4.state.scrollLeft - step }); this.grid4.scrollToPosition({ scrollLeft: this.grid4.state.scrollLeft - step });
} }
} }
} };
// 渲染表头 // 渲染表头
renderHeaderCell = ( renderHeaderCell = (
{ showColumns, position }: { showColumns: ColumnProps[]; position?: string }, { showColumns, position }: { showColumns: ColumnProps[]; position?: string },
...@@ -320,7 +329,15 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -320,7 +329,15 @@ export default class AirTable extends Component<TableProps, TableState> {
orderNo, orderNo,
} = showColumns[columnIndex]; } = showColumns[columnIndex];
return ( return (
<DragSorted columnName={columnName} orderNo={orderNo} 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={
...@@ -458,7 +475,6 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -458,7 +475,6 @@ export default class AirTable extends Component<TableProps, TableState> {
const scrollbarWidth = scrollbarSize() || 0; const scrollbarWidth = scrollbarSize() || 0;
const showColumns = this.memoizeColumns(columns); const showColumns = this.memoizeColumns(columns);
const leftColumns = this.memoizeLeftColumns(columns); const leftColumns = this.memoizeLeftColumns(columns);
const rightColumns = this.memoizeRightColumns(columns); const rightColumns = this.memoizeRightColumns(columns);
// 有隐藏列时,修正数据与列头不匹配问题 // 有隐藏列时,修正数据与列头不匹配问题
...@@ -486,7 +502,6 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -486,7 +502,6 @@ export default class AirTable extends Component<TableProps, TableState> {
<ScrollSync> <ScrollSync>
{({ onScroll, scrollLeft, scrollTop }: any) => { {({ onScroll, scrollLeft, scrollTop }: any) => {
return ( return (
<div <div
className={ className={
this.props.onScroll this.props.onScroll
...@@ -506,9 +521,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -506,9 +521,7 @@ export default class AirTable extends Component<TableProps, TableState> {
className={styles.leftSideContainer} className={styles.leftSideContainer}
style={{ style={{
width: `${leftWidth}px`, width: `${leftWidth}px`,
height: `${totalHeight - height: `${totalHeight - scrollbarWidth + headerHeight}px`,
scrollbarWidth +
headerHeight}px`,
}} }}
> >
{ {
...@@ -599,8 +612,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -599,8 +612,7 @@ export default class AirTable extends Component<TableProps, TableState> {
// 中部表头 // 中部表头
<div <div
style={{ style={{
backgroundColor: backgroundColor: 'rgba(246, 246, 246, 1)',
'rgba(246, 246, 246, 1)',
height: headerHeight, height: headerHeight,
width, width,
}} }}
...@@ -610,28 +622,20 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -610,28 +622,20 @@ export default class AirTable extends Component<TableProps, TableState> {
this.grid3 = dom; this.grid3 = dom;
}} }}
className={styles.headerGrid} className={styles.headerGrid}
overscanColumnCount={ overscanColumnCount={overscanColumnCount}
overscanColumnCount columnWidth={this.getColumnWidth.bind(this, {
} columns: showColumns,
columnWidth={this.getColumnWidth.bind( showColumns,
this, })}
{
columns: showColumns,
showColumns,
},
)}
columnCount={columnCount} columnCount={columnCount}
width={width} width={width}
rowHeight={headerHeight} rowHeight={headerHeight}
rowCount={1} rowCount={1}
height={headerHeight} height={headerHeight}
scrollLeft={scrollLeft} scrollLeft={scrollLeft}
cellRenderer={this.renderHeaderCell.bind( cellRenderer={this.renderHeaderCell.bind(this, {
this, showColumns,
{ })}
showColumns,
},
)}
/> />
</div> </div>
} }
...@@ -649,54 +653,39 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -649,54 +653,39 @@ export default class AirTable extends Component<TableProps, TableState> {
this.grid4 = dom; this.grid4 = dom;
}} }}
className={styles.centerGrid} className={styles.centerGrid}
overscanColumnCount={ overscanColumnCount={overscanColumnCount}
overscanColumnCount overscanRowCount={overscanRowCount}
} columnWidth={this.getColumnWidth.bind(this, {
overscanRowCount={ columns: showColumns,
overscanRowCount showColumns,
} })}
columnWidth={this.getColumnWidth.bind(
this,
{
columns: showColumns,
showColumns,
},
)}
columnCount={columnCount} columnCount={columnCount}
width={realWidth} width={realWidth}
rowHeight={rowHeight} rowHeight={rowHeight}
rowCount={rowCount} rowCount={rowCount}
onScroll={( onScroll={(...arg: Array<Object>) => {
...arg: Array<Object>
) => {
onScroll(...arg); onScroll(...arg);
this.onScroll(arg[0]); this.onScroll(arg[0]);
}} }}
scrollTop={scrollTop} scrollTop={scrollTop}
height={totalHeight} height={totalHeight}
cellRenderer={this.renderBodyCell.bind( cellRenderer={this.renderBodyCell.bind(this, {
this, showColumns,
{ showData,
showColumns, position: 'center',
showData, })}
position: 'center',
},
)}
/> />
) : ( ) : (
columnCount > 0 && columnCount > 0 &&
!loading && ( !loading && (
<Empty <Empty
className={ className={styles.defaultEmpty}
styles.defaultEmpty description={
} noDataPlaceholder || locale.empty
description={ }
noDataPlaceholder || />
locale.empty )
} )}
/>
)
)}
</div> </div>
} }
</div> </div>
...@@ -704,14 +693,26 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -704,14 +693,26 @@ export default class AirTable extends Component<TableProps, TableState> {
}} }}
</AutoSizer> </AutoSizer>
</div> </div>
{canFixed && (
<RightDragFixed
initLeft={tableWidth - rightWidth}
initTop={headerHeight}
tableWidth={tableWidth}
showColumns={showColumns}
columnWidth={columnWidth}
columns={columns}
scrollbarWidth={scrollbarWidth}
onResizeStart={this.onResizeStartRightDragFixed}
onResizeStop={this.onResizeStopLeftDragFixed}
/>
)}
{totalWidth > tableWidth && rightCount > 0 && ( {totalWidth > tableWidth && rightCount > 0 && (
<div <div
className={styles.rightSideContainer} className={styles.rightSideContainer}
style={{ style={{
width: `${rightWidth}px`, width: `${rightWidth}px`,
height: `${totalHeight - height: `${totalHeight - scrollbarWidth + headerHeight}px`,
scrollbarWidth + right: scrollbarWidth,
headerHeight}px`,
}} }}
> >
{ {
...@@ -785,10 +786,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -785,10 +786,7 @@ export default class AirTable extends Component<TableProps, TableState> {
</div> </div>
)} )}
<div className={styles.fillHandleWrapper} /> <div className={styles.fillHandleWrapper} />
<div <div className={styles.loading} style={{ top: `${totalHeight / 2}px` }}>
className={styles.loading}
style={{ top: `${totalHeight / 2}px` }}
>
{loading && (loadComp ? loadComp : <Spin />)} {loading && (loadComp ? loadComp : <Spin />)}
</div> </div>
<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