react+antd Table实现列拖拽,列拉宽,自定义拉宽列

发布于:2025-07-08 ⋅ 阅读:(21) ⋅ 点赞:(0)

主要插件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,慢慢改吧


网站公告

今日签到

点亮在社区的每一天
去签到