In recent months to do a project, the react project achieved eighty percent, then the inside of the business requirements project modal dialog can drag and drop, ha ha, not to mention early, late, just now, although my in the mind scold ten thousand times, but still can honestly make ah, after all, who call the somebody else is god, we mortals can only let them kill, not to say, Say too much are tears!

The UI framework used in the project is ANTD-Design, which is familiar to everyone who has developed react projects. It is almost the preferred UI library for react projects. After all, It is manufactured by Ali and has quality assurance, but what is really bad is that its Modal component does not have drag-and-drop function. Tracking relevant issues on Github, I did find several versions of the gods after transformation, and I verified them one by one, but there were always various problems, so I had to do it by myself. Time was tight, so I spent most of the day to do it, which was relatively simple and crude, and mainly realized the following functions

1. Click on the title area to start dragging, and lift the mouse to stop dragging 2. 3. For A page with multiple modal boxes, click A and then click B to place B above A. If the modal boxes in the project are not masked, it can be realized that whoever is clicked will appear on the topCopy the code

For:

1. The center attribute of Modal must be true, that is, vertically centered, otherwise the drag origin cannot be calculated accurately 2. Dragging is not smooth enoughCopy the code

Friendly use tips

1. For a page with multiple modal boxes, such as A -> B -> C, it is necessary to set the zIndex of A to a number greater than 1000. The subsequent values of B and C will increase successively, that is, ensure that C > B > A > 1000, otherwise there will be confusion. Forget to add cousor: Move to the custom title category of the modal boxCopy the code

Anyway, I just want to share my thoughts with you so that we can discuss and solve any problems we have in the future

The above functions basically meet the needs of our project, paste my code below, I have written notes in important places, if you don’t understand, please leave a message to me, I will try my best to help me when I have time


import React from "react";
import {Modal} from "antd"; Const createUniqID = length=>Number(math.random ().toString().substr(3,length) + Date.now()).toString(36); class AntdDragModal extends React.PureComponent { constructor(props) { super(props); this.id = createUniqID(10); this.dragWrapDom = null; // Element this.dragdom = null for the wrap drag element // Target element of drag, corresponding to element this.dragging = in the Modal component with class.antD-Modalfalse; This. tLeft = 0; // this.tTop = 0; // The offset of the upper-left corner of Modal relative to the upper-left corner of the screen, This. points = [0, 0] // drop this.rect = [0, 0, 0, Bind (this) this.onmouseup = this.onmouseup.bind (this) this.onmouseup = this.onmouseup.bind (this) this.onMouseMove = this.onMouseMove.bind(this) this.onContentMoseDown = this.onContentMoseDown.bind(this) }componentDidMount() {
        this.getDragDom();
    }
    
    componentDidUpdate() { this.getDragDom(); } /* * Use native methods to get dom in timer. * * /getDragDom() {
        setTimeout (() = > {/ / get the only markup elements const dragWrapDom = document. The getElementsByClassName (` d_${this.id}`) [0];if(dragWrapDom) { this.dragWrapDom = dragWrapDom; // Get the real drag elementlet dragDom = dragWrapDom.getElementsByClassName('ant-modal') [0]if (dragDom) {
                    this.dragDom = dragDom
                    let modalWidth = this.dragDom.offsetWidth;
                    let modalHeight = this.dragDom.offsetHeight;
                    let screenWidth = window.innerWidth
                    letScreenHeight = window.innerheight // The origin is not the upper-left corner of the screen, since dragDom is positioned relative to each other, and is centered horizontally and vertically at the beginning, So the origin is dragDom's offset from the top left corner of the screen this.points = [(screenWidth-modalWidth) / 2, (screenHeight - modalHeight) / 2] this.rect = [screenWidth, screenHeight, modalWidth, modalHeight] } } }); }; onMouseDown(e) { e.preventDefault(); this.dragging =true; // Enable drag state /* ** The current floating layer on top * * will cover all current can drag and drop the supernatant zIndex = 999 * * the current drag-and-drop target zIndex = 1000 * * / const nodeList = document. GetElementsByClassName ("drag_modal");
        if (nodeList.length > 0) {
            Array.from(nodeList).forEach(item => {
                item.style.zIndex = 999
                if(item.previousElementSibling) { item.previousElementSibling.style.zIndex = 999 } }); this.dragWrapDom.style.zIndex = 1000; /* ** If the mask property is set totrue, this. DragWrapDom. * * ntSibling previousEleme is layer, layer of the zIndex needs and their modal frame synchronization, no * * multiple modal dialog click on a page will disorder * /if(this.dragWrapDom.previousElementSibling) { this.dragWrapDom.previousElementSibling.style.zIndex = 1000; } } /* * getBoundingClientRect: Return a DomRect object * containing the top, right, bottom, and left values of the element, corresponding to the distance to the top and left of the screen, * * / unit px const dragDomRect = this. DragDom. GetBoundingClientRect (); This. tLeft = e.clientx-dragdomRect.left +; /* * e.clientx-dragdomRect.left +; /* * e.clientx - dragdomRect.left +; /* * e.clientx - dragdomRect.left +; /* * e.clientx - dragdomRect.left + this.points[0]; this.tTop = e.clientY - dragDomRect.top + this.points[1]; this.onMouseMove(this.dragDom); }; onMouseUp(e) { e.preventDefault(); this.dragging =false; Document. onMousemove = null; // Stop mouse movement events}; onMouseMove(node) { document.onmousemove = e => { e.preventDefault();if (this.dragging) {
                let left = e.clientX - this.tLeft
                letTop = e.clienty - this.tTop // Make sure the modal box is in viewif (this.points[0] + left > 0 && this.points[0] + left + this.rect[2] < this.rect[0]) {
                    if (this.points[1] + top > 0 && this.points[1] + top + this.rect[3] < this.rect[1]) {
                        node.style.left = left + 'px';
                        node.style.top = top + 'px'; }}}}; }; // Click the Content part of Modal to also stop dragging the modal box onContentMoseDown(e) {this.dragging =false; 
        document.onmousemove = null; 
    }


    render() { const { zIndex = 999, children, wrapClassName title, width = 520, ... otherProps } = this.propsreturn (
            <Modal
                zIndex={zIndex}
                width={width}
                wrapClassName={`drag_modal d_${this.id} ${wrapClassName}`}
                title={
                    <div
                        className="drag_title"onMouseDown={this.onMouseDown} onMouseUp={this.onMouseUp} > {title} </div> } {... otherProps} centered={true} > <div onMouseDown={this.onContentMoseDown}> {children} </div> </Modal> ); }}export default AntdDragModal;

Copy the code