当前位置:网站首页>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语言小项目 -- 通讯录(静态版+动态版+文件版)
(7)FlinkSQL将kafka数据写入到mysql方式二
连锁小酒馆第一股,海伦司能否梦圆大排档?
Pointer and array written test questions analysis
R语言ggplot2可视化:使用ggpubr包的ggbarplot函数可视化堆叠的柱状图(stacked bar plot)、palette参数自定义不同水平柱状图边框以及填充的颜色
优刻得“失速”:营收转降,定向增发股东浮亏超三成
2022-08-03
Five-faced Alibaba rated P6 after taking the offer: share his interview experience
萤石、小米对垒智能摄像头
请问如何实现两个不同环境的MySQL数据库实时同步
(5) FlinkSQL writes socket data to mysql Method 2
Codeblocks安装与配置教程
华中科大提出VGNetG:“不做选择,全都要”轻量化主干网络!
Fluorite, millet against smart camera
[C language] Dynamic memory management
“自降估值”3个亿的咖啡独角兽要IPO了
odps sql被删除了,能找回来吗
R语言ggpubr包的ggsummarystats函数可视化分面箱图(通过ggfunc参数和facet.by参数设置)、添加描述性统计结果表格、palette参数配置不同水平可视化图像和统计值的颜色
北京 北京超大旧货二手市场开集了,上千种产品随便选,来的人还真不少
详解轮播图二-通过left定位来轮播图片