react how to drag a modal box

In the actual development, the modal box display data will often appear Unfortunately, sometimes when the function is developed, the UI students suddenly put forward a demand, hoping that the modal box can be dragged How to implement drag and drop without modifying the original code The final effect drawing is as follows:

practice

1. Create a high-level component DragHoc

Create a new file modaldrag / index JS, copy the following code

DragObj is the specific drag and drop native js code, which will be seen later

  • DragHoc is a function for creating high-order components. The parameter InnerComponent is the modal box component that needs to be modified, and the final return value of the function is the enhanced component

  • The render method directly returns \, but does not return a new component The function of the whole high-order component is to add a ref attribute to the input component With ref, the init method can use reactdom Finddomnode gets the native dom of any component passed in After you get the DOM, you can do the underlying DOM operation or event binding to realize drag and drop

  • init method adds a timer with a delay of 0s, because InnerComponent in my project is encapsulated by Modal in ant design During debugging, reactdom findDOMNode can only return dom elements that have been mounted on the page, otherwise it returns null The Modal rendering content in ant design is asynchronous, so you need to use a timer to wait until the next frame to use findDOMNode to get the dom element of the component If the InnerComponent does not contain asynchronous rendering code, the following timer can be deleted

  • When the component is unloaded, call the destroy method to release all bound events

Dragging an element usually requires passing in two parameters One is the area that can be moved after pushing and dragging, which corresponds to the whole export table control in the figure above. The class name of the control is main_class. The other is the monitoring and dragging area, which corresponds to the head in the figure above. The table can be dragged only when the mouse is pressed on the head and then moved The class name of the head is title_class. Both parameters are passed in from the outside If both parameters are not passed, the default is to directly listen to the child_node and drag child_node

import React from 'react';
import ReactDOM from 'react-dom';
import DragObj from './drag';

//main_class and title_class is the class name
export const DragHoc = (InnerComponent,main_class,title_class) =>
  class extends React.Component {
    componentDidMount() {
      this.init();
    }

    init = () => {
      setTimeout(() => {
        const child_node = ReactDOM.findDOMNode(this.refs.child); //Get the native dom element
        if (child_node) {
          this.drag_obj = new DragObj(
            main_class?child_node.querySelector(`.${main_class}`):child_node, //Drag only div with class name ${main_class}
            title_class?child_node.querySelector(`.${title_class}`):child_node //Dragging is allowed only when the mouse is pressed on the div with the class name ${title_class}
          );
        }
      }, 0);
    };

    componentWillUnmount() {
      if (this.drag_obj) {
        this.drag_obj.destory();
      }
    }

    render() {
      return <InnerComponent {...this.props} ref="child" />;
    }
  };

Copy code

If you find that dragging is invalid in practice, be sure to use the child in the above code_ Print out the node and observe whether the real dom is obtained and whether its internal rendering is complete If the rendering is not complete, it means that InnerComponent contains asynchronous rendering code. Drag event binding can be performed after rendering is completed

2. Create drag class DragObj

Create a new file modaldrag / drag JS, copy the following code

The following is the native code for drag and drop It is mainly responsible for binding dom elements to events and changing positions

export default class DragObj {
  start_x0 = 0;
  start_y0 = 0;
  start_x1 = 0;
  start_y1 = 0;
  state = false; //Record whether the mouse button is released
  delta_x = 0; //Lateral offset from original position
  delta_y = 0; //Longitudinal offset from original position

  constructor(target, move_item) {
    this.target = target; //dom element moved
    this.move_item = move_item; //Accept the dom element that triggers the movement behavior, usually the head of the modal box
    this.init();
  }

  init() {
    this.move_item.style.cursor = 'move';
    this.bindEvent();
  }

  destory() {
    this.move_item.removeEventListener('mousedown', this.moveStartFun);
    document.removeEventListener('mousemove', this.movingFun);
    document.removeEventListener('mouseup', this.moveEndFun);
  }

  bindEvent() {
    this.moveStartFun = this.moveStart.bind(this);
    this.movingFun = this.moving.bind(this);
    this.moveEndFun = this.moveEnd.bind(this);
    this.move_item.addEventListener('mousedown', this.moveStartFun);
    document.addEventListener('mousemove', this.movingFun);
    document.addEventListener('mouseup', this.moveEndFun);
  }

  moveStart(e) {
    e.stopPropagation();
    this.state = true; //Check whether the mouse is pressed
    this.start_x0 = e.pageX;
    this.start_y0 = e.pageY;
  }

  moving(e) {
    //Default action when moving the mouse
    e.stopPropagation();
    e.preventDefault();
    if (!this.state) {
      return false;
    }

    this.start_x1 = e.pageX;
    this.start_y1 = e.pageY;
    this.render();
  }

  moveEnd(e) {
    if (!this.state) {
      return false;
    }
    this.state = false;
    this.delta_x = this.start_x1 - this.start_x0 + this.delta_x;
    this.delta_y = this.start_y1 - this.start_y0 + this.delta_y;
  }

  render() {
    this.target.style.transform = `translate(${
      this.start_x1 - this.start_x0 + this.delta_x
    }px,${this.start_y1 - this.start_y0 + this.delta_y}px)`;
  }
}
Copy code

3. External call

The high-order function DragHoc is introduced, and the modal box component ToastExport that needs to be enhanced is introduced

Because the author uses the Modal component in ant design 3.0 as the Modal box in the project, to drag it, only need to pass the class names "ant Modal content" and "ant Modal header"

Other scenarios need to analyze which part is to be moved and which part is to be monitored and dragged according to the dom structure of the static modal box component, and pass the class names of these two parts as parameters

import { DragHoc } from "./index.js";
import ToastExport from "../components/ToastExport/index.js";//Introduce static modal box components (user-defined modal box components)
const ToastExportv2 = DragHoc(ToastExport,"ant-modal-content","ant-modal-header"); //A modal box component with drag function is generated
 Copy code

After calling DragHoc function to generate ToastExportv2, it can be used directly on the page If the business needs to transfer parameters, they are directly added to the attribute

   const { visible } = this.props;
   <ToastExportv2 visible={visible}/>

Author: Kay_
Link: https://juejin.im/post/6886418005107376142
Source: Nuggets
The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source.

Posted by lhale on Tue, 10 May 2022 05:33:44 +0300