需求
React在使用antd项目中需要使用Model弹框,弹框展示(弹出时),需要可以拖拽移动弹框,并且不能超过可视范围。
代码
/* eslint-disable prefer-destructuring */
import type { MouseEvent } from 'react';
import React, { Component } from 'react';
import type { ModalProps } from 'antd/lib/modal';
// import AntdModal from 'antd/lib/modal';
/* 可以将model换成上方注释的AntdModal ,将下方一行注释,放出上方一行代码,在使用Model的地方替换成AntdModal 。 */
/* 解释:使用AntdModal 时,按钮是英文,使用Model,是因为按钮按现在有的语言环境展示的*/
import { Modal } from 'antd';
import 'antd/es/modal/style/index.css';
export default class AntDraggableModal extends Component<ModalProps> {
private simpleClass: string;
private header: any;
private contain: any;
private modalContent: any;
private mouseDownX: number = 0;
private mouseDownY: number = 0;
private deltaX: number = 0;
private deltaY: number = 0;
private sumX: number = 0;
private sumY: number = 0;
private offsetLeft: number = 0;
private offsetTop: number = 0;
constructor(props: ModalProps) {
super(props);
this.simpleClass = Math.random().toString(36).substring(2);
}
handleMove = (event: any) => {
const deltaX = event.pageX - this.mouseDownX;
const deltaY = event.pageY - this.mouseDownY;
this.deltaX = deltaX;
this.deltaY = deltaY;
let tranX = deltaX + this.sumX;
let tranY = deltaY + this.sumY;
// 左侧
if (tranX < -this.offsetLeft) {
tranX = -this.offsetLeft;
}
// 右侧
const offsetRight =
document.body.clientWidth -
this.modalContent.parentElement.offsetWidth -
this.offsetLeft;
if (tranX > offsetRight) {
tranX = offsetRight;
}
// 上侧
if (tranY < -this.offsetTop) {
tranY = -this.offsetTop;
}
// 下侧
const offsetBottom =
document.body.clientHeight -
this.modalContent.parentElement.offsetHeight -
this.offsetTop;
if (tranY > offsetBottom) {
tranY = offsetBottom;
}
this.modalContent.style.transform = `translate(${tranX}px, ${tranY}px)`;
};
initialEvent = (visible: boolean) => {
const { title } = this.props;
if (title && visible) {
setTimeout(() => {
window.removeEventListener('mouseup', this.removeUp, false);
this.contain = document.getElementsByClassName(this.simpleClass)[0];
this.header = this.contain.getElementsByClassName('ant-modal-header')[0];
this.modalContent = this.contain.getElementsByClassName('ant-modal-content')[0];
this.offsetLeft = this.modalContent.parentElement.offsetLeft;
this.offsetTop = this.modalContent.parentElement.offsetTop;
this.header.style.cursor = 'all-scroll';
this.header.onmousedown = (e: MouseEvent<HTMLDivElement>) => {
this.mouseDownX = e.pageX;
this.mouseDownY = e.pageY;
document.body.onselectstart = () => false;
window.addEventListener('mousemove', this.handleMove, false);
};
window.addEventListener('mouseup', this.removeUp, false);
}, 0);
}
};
removeMove = () => {
window.removeEventListener('mousemove', this.handleMove, false);
};
removeUp = () => {
// document.body.onselectstart = () => true;
this.sumX += this.deltaX;
this.sumY += this.deltaY;
this.deltaX = 0;
this.deltaY = 0;
if (this.sumX < -this.offsetLeft) {
this.sumX = -this.offsetLeft;
}
const offsetRight =
document.body.clientWidth -
this.modalContent.parentElement.offsetWidth -
this.offsetLeft;
if (this.sumX > offsetRight) {
this.sumX = offsetRight;
}
// 上侧
if (this.sumY < -this.offsetTop) {
this.sumY = -this.offsetTop;
}
// 下侧
const offsetBottom =
document.body.clientHeight -
this.modalContent.parentElement.offsetHeight -
this.offsetTop;
if (this.sumY > offsetBottom) {
this.sumY = offsetBottom;
}
this.removeMove();
};
componentDidMount() {
const { visible = false } = this.props;
this.initialEvent(visible);
}
componentWillReceiveProps(newProps: any) {
const { visible } = this.props;
if (newProps.visible && !visible) {
this.initialEvent(newProps.visible);
}
if (visible && !newProps.visible) {
this.removeMove();
window.removeEventListener('mouseup', this.removeUp, false);
}
}
componentWillUnmount() {
this.removeMove();
window.removeEventListener('mouseup', this.removeUp, false);
}
render() {
const { children, wrapClassName, ...other } = this.props;
const wrapModalClassName = wrapClassName
? `${wrapClassName} ${this.simpleClass}`
: `${this.simpleClass}`;
return (
<Modal {...other} wrapClassName={wrapModalClassName}>
{children}
</Modal>
);
}
}
展示效果
自行复制代码去测试吧。
引用
本效果是借鉴 Ant-design Modal实现可以拖动的效果代码修改得到的。