当前位置:网站首页>TS+Hooks二次封装antd Modal,实现可拖拽
TS+Hooks二次封装antd Modal,实现可拖拽
2022-08-08 12:55:00 【Buliang_C】
一、最终效果图
使用Typescript和React Hooks二次封装antd的Modal对话框,实现可拖拽效果,并且满足下面的小细节。最终效果图如下:
小细节:
- 拖动时鼠标于DIV的相对位置
- 拖动时选中文字
- 边界问题
- 页面失去焦点
- 销毁时回到原位

二、可拖动DIV
在实现Modal对话框拖拽的之前,可以在html页面上先实现一个可拖动的DIV,我是学习了这篇文章可拖动DIV。里面的具体原理细节可以参考这篇文章。
直接通过图的方式表达可能更加直观。主要就是要确定好相对移动距离和边界条件。我的在线测试DEMO

三、封装ModalBox
1. 实现原理
- 有部分参考了这篇文章,antd Modal的class属性是ant-modal-content,通过这个属性,获得Modal对话框具体左右视图边框的距离contentLeft和contentRight,用于后续的定位。


- 相对移动位置
var cx = e.clientX - startPosX + styleLeft,
cy = e.clientY - startPosY + styleTop;
- Modal对话框位置再次点击更新
这里的132就是Modal高度的一半,为了让他销毁后每次都保持在视图中央。如果自己改变宽高度的话,可以再次封装style中的width,就不至于写死了。因为Modal组件关闭的时候,是不会自动销毁的,如果不写下面的代码,会导致再次点开Modal后,还是上次那个位置。这个地方写的不太好,继续优化。
useEffect(() => {
return () => {
setStyleLT({
styleLeft: 0,
styleTop: window.innerHeight / 2 - 132
})
setFlag(true);
}
}, [props.isModalVisible])
2.ModalBox 组件代码
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;
4. 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每次消失的时候,不太流畅,需要再次优化,如果有好的建议,希望能和我一起交流。(* ̄︶ ̄)
边栏推荐
猜你喜欢
随机推荐
Docker-持久化数据库(数据卷)
(4)FlinkSQL将socket数据写入到mysql方式一
[C language] Dynamic memory management
Promise 解决阻塞式同步,将异步变为同步
简析LDO静态电流与功耗的关系
直接选择排序
DDoS攻击为什么是无解的
R语言patchwork包将多个ggplot2可视化结果组合起来、使用plot_annotation函数以及tag_level参数为组合图添加自定义编码序列(字符向量列表)
爱可可AI前沿推介(8.8)
Win10环境下使用Flask配合Celery异步推送实时/定时消息(Socket.io)/2020年最新攻略
面试官问你什么是长轮询?
R语言ggplot2可视化:使用ggpubr包的ggline函数可视化折线图(点线图、line plot)、设置add参数为mean可视化不同水平均值的折线图
“自降估值”3个亿的咖啡独角兽要IPO了
【重构map】【重构filter】【重构Some】【重构reduce方法】【重构flat函数】
The use of qsort function and its analog implementation
Knowledge points and written test questions related to shift operations, bit operations, and logical operations
删库不易,跑路更难
手绘地图制作的关键点之“图层覆盖”
RT-Thread记录(三、RT-Thread 线程操作函数及线程管理与FreeRTOS的比较)
一文读懂配置管理(CM)


![[C language] file related operations](/img/bb/95a5acc1c8e780c1ed46c9c8ab0543.png)






