How to drag and drop the modal box in react

Preface

In actual development, modal box display data will often appear. But unfortunately, sometimes after the function is developed, UI students suddenly demand that the modal box can be dragged. The modal box used in this article is encapsulated by the Modal component of ant design 3.0 Yes, how to implement drag and drop without modifying the original code. The final rendering is as follows:

Insert picture description here

practice

1. Create a higher-order component DragHoc

Create a new file ModalDrag/index.js and copy the following code into it

DragObj is the native js code for specific drag and drop, see later

  • DragHoc is a function to create higher-order components, where the parameter InnerComponent is the modal component that needs to be transformed, and the final return value of the function is the enhanced component

  • The render method directly returns <InnerComponent/> and does not return a new component. The role of the entire high-level component is only to add a ref attribute to the input component. With ref, the init method can be obtained through ReactDOM.findDOMNode. The native dom of any component you import. After you get the dom, you can do the underlying dom operation or event binding to achieve drag and drop

  • A timer with a delay of 0s is added to the init method. Because the InnerComponent in the author's project is encapsulated with Modal in ant design. During the debugging process, I found that ReactDOM.findDOMNode can only return the dom that has been mounted on the page. Element, otherwise it returns null. And the Modal rendering content in ant design is asynchronous, so you have to use the timer to wait until the next frame to use findDOMNode to get the dom element of the component. If InnerComponent does not contain asynchronous rendering code, the following timer can delete

  • Call the destroy method when the component is uninstalled to release all bound events

Dragging an element usually requires passing in two parameters. One is the area that can be moved after being pushed, which corresponds to the entire exported table control in the above figure, and the class name of the control is main_class. The other is the area that monitors the drag, corresponding With the head in the figure above, the table can only be dragged when the mouse is moved when the head is pressed. The class name of the head is title_class. Both parameters are passed in from the outside. If neither parameter is passed, the default Directly monitor child_node and drag child_node


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

//main_class和title_class都是类名
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); //获取到原生的dom元素
        if (child_node) {
          this.drag_obj = new DragObj(
            main_class?child_node.querySelector(`.${main_class}`):child_node, //只拖拽类名为 ${main_class} 的div
            title_class?child_node.querySelector(`.${title_class}`):child_node //当鼠标按在类名为 ${title_class} 的div上时才允许拖拽
          );
        }
      }, 0);
    };

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

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


If you find that dragging is invalid in practice, please be sure to print out the child_node in the above code, and observe whether you have obtained the real dom and whether it is rendered complete. If the rendering is not complete, it means that InnerComponent contains asynchronous rendering code, and you have to wait until rendering After finishing drag and drop event binding


2. Create a drag and drop class DragObj

Create a new file ModalDrag/drag.js and copy the following code into it

The following is the native code to implement drag and drop. It is mainly responsible for event binding and changing position of dom elements.

export default class DragObj {
  start_x0 = 0;
  start_y0 = 0;
  start_x1 = 0;
  start_y1 = 0;
  state = false; //记录鼠标按键是否松开
  delta_x = 0; //相对于原始位置的横向偏移量
  delta_y = 0; //相对于原始位置的纵向偏移量

  constructor(target, move_item) {
    this.target = target; //被移动的dom元素
    this.move_item = move_item; //接受触发移动行为的dom元素,一般为模态框的头部
    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; //检测鼠标是否处于按下的状态
    this.start_x0 = e.pageX;
    this.start_y0 = e.pageY;
  }

  moving(e) {
    //鼠标移动时的默认操作
    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)`;
  }
}

3. External call

Introduce the higher-order function DragHoc, and introduce the modal component ToastExport that needs to be enhanced

Since the author uses the Modal component in ant design 3.0 as the modal box in the project, dragging it only needs to pass the class name "ant-modal-content" and "ant-modal-header".

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


import { DragHoc } from "./index.js";
import ToastExport from "../components/ToastExport/index.js";//引入静态的模态框组件(用户自已定义的模态框组件)
const ToastExportv2 = DragHoc(ToastExport,"ant-modal-content","ant-modal-header"); //生成了具备拖拽功能的模态框组件

After calling the DragHoc function to generate ToastExportv2, it can be used directly on the page. If the business needs to pass parameters, add them directly to the attributes


   const { visible } = this.props;  //visible控制显示隐藏模态框
   {visible?<ToastExportv2 visible={visible}/>:null}

When calling, you need to pay attention to rendering ToastExportv2 when visible is true, in order to prevent the dom from rendering when the event is bound. When visible is false, the destruction of the component will automatically call the destroy method to unbind the registered event

Guess you like

Origin blog.csdn.net/brokenkay/article/details/109229686