使用react-draggable和react-resizable实现Ant Design Modal的拖动和拖拽改变宽度
需求
Ant Design 提供的Modal是不支持拖动还有侧边拖拽改变宽度的,基于这一点我们需要自定义一个我们自己的Modal组件,来实现拖动和拖拽改变宽度。
其中会用到的技术有:使用react-draggable
来实现modal的拖动,使用react-resizable
来实现拖拽改变宽度。
实现
首先实现拖动这个比较简单,直接引入react-draggable
,然后使用<Draggable>
包裹一下就可以了,网上案例很多,不具体讲。 唯一比较特别的是,如果你直接包裹在<Modal>
外面是无法实现拖拽的,而是要在<Modal>
中的modalRender
属性中进行<Draggable>
的包裹。还有一点需要注意的是拖动的时候需要设置一下不能超出当前可视窗口。
实现拖拽改变宽度也不难,也是引入react-resizable
,然后用<Resizable>
包裹一下就可以了,但是需要设置width
,并且是number
类型。还有一点需要注意的是,需要设置一下modal最小的宽度,防止拖拽改变宽度太小导致modal里面的内容样式错乱。
参考代码
import Draggable, {DraggableBounds, DraggableData, DraggableEvent} from 'react-draggable'
import {Modal, ModalProps} from "antd";
import React, {useLayoutEffect, useRef, useState} from "react";
import './index.css';
import {Resizable} from "react-resizable";
interface DraggableModalProps extends ModalProps {
modalMinWidth?: number,
width?: number
}
const DraggableModal: React.FC<DraggableModalProps> = (props: any) => {
const [bound, setBound] = useState<DraggableBounds>({left: 0, top: 0, bottom: 0, right: 0})
const modalRef = useRef();
const draggableRef = useRef();
const {children, ...other} = props;
const [resizableWidth, setResizableWidth] = useState<number>(props.width || 0);
const resizeableSpaceWidth = 5;
const defaultMinSize = 400;
const onStart = (event: DraggableEvent, draggableData: DraggableData) => {
const {clientWidth, clientHeight} = window?.document?.documentElement;
const targetRect = (draggableRef?.current as any)?.getBoundingClientRect();
setBound({
left: -targetRect?.left + draggableData?.x,
right: clientWidth - (targetRect?.right - draggableData?.x) - resizeableSpaceWidth,
top: -targetRect?.top + draggableData?.y,
bottom: clientHeight - (targetRect?.bottom - draggableData?.y)
})
};
useLayoutEffect(() => {
setResizableWidth(props.width || defaultMinSize);
}, [props.width])
const onResize = (e: React.SyntheticEvent<Element, Event>, {size}: any) => {
if (size.width < (props.modalMinWidth || defaultMinSize)) {
setResizableWidth(props.modalMinWidth || defaultMinSize);
} else {
setResizableWidth(size.width);
}
}
return (
<Modal {...other} ref={modalRef}
width={resizableWidth}
modalRender={modal => (
<Draggable handle={'.ant-modal-header'}
bounds={bound}
onStart={(event, uiData) => onStart(event, uiData)}>
{/* @ts-ignore*/}
<div ref={draggableRef} className={'draggable-modal'}>
<Resizable width={resizableWidth} height={0}
onResize={onResize}>
{modal}
</Resizable>
</div>
</Draggable>
)}>
{children}
</Modal>
);
}
export default DraggableModal;
参考
React Draggable 实现拖拽 - 最详细中文教程 - 卡拉云
React 拖拽改变大小,react-resizable 属性详解