当前位置:网站首页>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每次消失的时候,不太流畅,需要再次优化,如果有好的建议,希望能和我一起交流。(* ̄︶ ̄)
边栏推荐
- 【C语言】动态内存管理
- Study: Toxic PFAS chemicals make rainwater unsafe to drink around the world
- 什么是IP SSL证书,如何申请?
- 简析LDO静态电流与功耗的关系
- 迁移学习(Transfer Learning)的背景、历史及学习课
- 【JS高级】ES5标准规范之严格模式下的保护对象_09
- MySQL database storage series (5) the InnoDB storage format
- 手绘地图制作的关键点之“图层覆盖”
- R语言基于指定规则、条件删除列表中的元素:使用purrr包的discard函数移除列表数据中的NA值
- qsort 函数的使用及其模拟实现
猜你喜欢
随机推荐
使用shardingjdbc实现读写分离配置
什么是IP SSL证书,如何申请?
The maximum validity period of an SSL certificate is 13 months. Is it necessary to apply for multiple years at a time?
Background, History and Lessons of Transfer Learning
(6) FlinkSQL writes kafka data to mysql Method 1
Docker-持久化数据库(数据卷)
北京 北京超大旧货二手市场开集了,上千种产品随便选,来的人还真不少
将小部分源码设计精髓带入到开发中来(工厂模式、适配器模式、抽象类、监听器)
Doris学习笔记之优化
宏任务和微任务——三目算符与加号优先级——原生的js如何禁用button——0xff ^ 33 的结果是——in的用法——正则匹配网址
【C语言】深度剖析数据在内存中的存储
一些常见的web小功能
OFD是什么
R语言基于指定规则、条件删除列表中的元素:使用purrr包的discard函数移除列表数据中的NA值
MySQl表的增删查改(CRUD)
一文搞懂│XSS攻击、SQL注入、CSRF攻击、DDOS攻击、DNS劫持
程序环境和预处理
Three classic topics in C language: three-step flip method, Young's matrix, and tossing and dividing method
2022-08-04
DDoS攻击为什么是无解的