使用Typescript和React Hooks二次封装antd的Modal对话框,实现可拖拽效果,并且满足下面的小细节。最终效果图如下:
在实现Modal对话框拖拽的之前,可以在html页面上先实现一个可拖动的DIV,我是学习了这篇文章可拖动DIV。里面的具体原理细节可以参考这篇文章。
直接通过图的方式表达可能更加直观。主要就是要确定好相对移动距离和边界条件。我的在线测试DEMO
var cx = e.clientX - startPosX + styleLeft,
cy = e.clientY - startPosY + styleTop;
useEffect(() => {
return () => {
setStyleLT({
styleLeft: 0,
styleTop: window.innerHeight / 2 - 132
})
setFlag(true);
}
}, [props.isModalVisible])
import { Modal } from 'antd';
import { useState, useEffect } from 'react';
interface ModalBoxxProps {
title: string,
isModalVisible: boolean,
handleOk: any,
handleCancel: any,
children?: React.ReactNode,
okText?: string,
cancelText?: string
}
let content: HTMLDivElement, contentLeft: number = 0, contentRight: number = 0;
const ModalBox: React.FC<ModalBoxxProps> = (props) => {
const [styleLT, setStyleLT] = useState({
styleLeft: 0, styleTop: window.innerHeight / 2 - 132
});
let [flag, setFlag] = useState<boolean>(true);
const style = { left: styleLT.styleLeft, top: styleLT.styleTop }
useEffect(() => {
return () => {
setStyleLT({
styleLeft: 0,
styleTop: window.innerHeight / 2 - 132
})
setFlag(true);
}
}, [props.isModalVisible])
const onMouseDown = (e: any) => {
e.preventDefault();
if (flag) {
content = document.getElementsByClassName("ant-modal-content")[0] as HTMLDivElement;
contentLeft = content.getBoundingClientRect().left;
contentRight = content.getBoundingClientRect().right - content.offsetWidth;
setFlag(false);
}
// 记录初始移动的鼠标位置
const startPosX = e.clientX
const startPosY = e.clientY;
const { styleLeft, styleTop } = styleLT
// 添加鼠标移动事件
document.onmousemove = (e) => {
var cx = e.clientX - startPosX + styleLeft,
cy = e.clientY - startPosY + styleTop;
if (cx < -contentLeft) {
cx = -contentLeft;
}
if (cy < 0) {
cy = 0;
}
if (cx > contentRight) {
cx = contentRight;
}
if (window.innerHeight - cy < content.offsetHeight) {
cy = window.innerHeight - content.offsetHeight;
}
setStyleLT({
styleLeft: cx,
styleTop: cy
})
}
// 鼠标放开时去掉移动事件
document.onmouseup = function (e) {
document.onmousemove = null
if (e.clientX > window.innerWidth || e.clientY < 0 || e.clientX < 0 || e.clientY > window.innerHeight) {
document.onmousemove = null
}
}
}
return (
<Modal
title={<div
className='dragBoxBar'
style={{ height: "100", width: "100%", cursor: 'move', userSelect: "none" }}
onMouseDown={onMouseDown}
>
{props.title}
</div>}
visible={props.isModalVisible}
onOk={props.handleOk}
onCancel={props.handleCancel}
style={style}
wrapClassName='dragBox'
okText={props.okText}
cancelText={props.cancelText}
>
{props.children}
</Modal>
)
}
export default ModalBox;
import { Button } from "antd";
import { useState } from "react";
// 引入组件
import { ModalBox } from "../Components";
interface ListProps {
name?: string,
age?: number
}
const List = (props: ListProps) => {
const [showModal, setShowModal] = useState<boolean>(false)
const handleModal = () => {
setShowModal(true);
}
const handleOk = () => {
setShowModal(false);
};
const handleCancel = () => {
setShowModal(false);
};
return (
<>
<div>列表页组件</div>
<ModalBox
title="告警信息"
isModalVisible={showModal}
handleOk={handleOk}
handleCancel={handleCancel}
okText="确定"
cancelText="取消"
>
<p>告警</p>
<p>告警</p>
<p>告警</p>
</ModalBox>
<Button onClick={handleModal}>点击弹窗</Button>
</>
)
}
export default List;
Modal每次消失的时候,不太流畅,需要再次优化,如果有好的建议,希望能和我一起交流。(* ̄︶ ̄)