主要插件Resizable,dnd-kit/core,dnd-kit/sortable,dnd-kit/modifiers
其中官网有列拖拽,主要结合Resizable 实现列拉宽,isResizingRef 很重要防止拖拽相互影响
1.修改TableHeaderCell
const isResizingRef = useRef(false);
const TableHeaderCell = props => {
const { onResize, width, datagridRef, stretchRef, ...restProps } = props;
// 拖拽
const dragState = useContext(DragIndexContext);
const { attributes, listeners, setNodeRef, isDragging } = useSortable({ id: props.id });
const isFixed = props['data-fixed'] && !isResizingRef.current;
const style = {
...props.style,
...(isFixed ? {} : { cursor: 'move' }),
...(isDragging ? { position: 'relative', userSelect: 'none' } : {}),
...dragActiveStyle(dragState, props.id),
};
const [offset, setOffset] = useState(0);
if (!width) {
return <th {...restProps} />;
}
// 获取要减去的父元素距离左侧的宽度
const getPosition = (element) => {
let actualLeft = element.offsetLeft;
let current = element.offsetParent;
while (current !== null) {
//当它上面有元素时就继续执行
actualLeft += current.offsetLeft;
current = current.offsetParent; //继续找父元素
}
return { x: actualLeft };
};
// 开始拖拽组织冒泡
const handleResizeStart = (e, { size }) => {
// console.log(233,e);
e.stopPropagation()
e.preventDefault()
isResizingRef.current = true; // ✅ 开始 resize
}
const handleResize = (e, { size }) => {
// 这里只更新偏移量,数据列表其实并没有伸缩
isResizingRef.current = true; // ✅ 开始 resize
setOffset(size.width - width);
let parentNodeX = getPosition(datagridRef.current).x;
let stretchDom = stretchRef.current;
stretchDom.style.display = 'block';
stretchDom.style.left = `${e.clientX - parentNodeX + 2}px`;
};
const handleResizeStop = (...arg) => {
// 拖拽结束以后偏移量归零
isResizingRef.current = false; // ✅ 结束 resize
setOffset(0);
let stretchDom = stretchRef.current;
stretchDom.style.display = 'none';
stretchDom.style.left = `0px`;
// props传进来的事件,在外部是列数据中的onHeaderCell方法提供的事件
// console.log(...arg, "arg9");
onResize(...arg);
};
const _ResizableSpan = (
<div
className="react-resizable-handle"
// 拖拽层偏移
style={{ transform: `translateX(${offset}px)` }}
onClick={(e) => {
// 取消冒泡,不取消貌似容易触发排序事件
e.stopPropagation();
e.preventDefault();
}}
/>
);
// console.log(isResizingRef.current, "isResizingRef.current");
return (
<Resizable
width={width + offset}
handle={_ResizableSpan}
height={0}
// 拖拽事件实时更新
onResize={handleResize}
// 拖拽结束更新
onResizeStop={handleResizeStop}
draggableOpts={{ enableUserSelectHack: false }}
onResizeStart={handleResizeStart}
>
<th {...restProps}
ref={isFixed && !isResizingRef.current ? undefined : setNodeRef}
style={style}
{...(isFixed && !isResizingRef.current ? {} : attributes)}
{...(isFixed && !isResizingRef.current ? {} : listeners)} />
</Resizable>
);
};
2.handleResize 拉宽后处理
// 处理拖拽
const handleResize =
(key) =>
(e, { size }) => {
if (size.width < 140) {
size.width = 140;
}
console.log(key, size.width, 9000);
setColumns(prev => {
const next = prev.map(col => {
if (col.dataIndex === key) {
return { ...col, width: size.width };
}
return col;
});
columRef.current = next;
return next;
});
};
总结来说,样式丑点,目前预测还会碰到未知bug,拉宽的同时会出现回弹之类的bug,慢慢改吧