AntdDraggableModal.js 5.9 KB
import React from 'react';
import { Modal } from 'antd';
import './AntdDraggableModal/antDraggle.less';


class AntDraggableModal extends React.Component {
  constructor(props) {
    super(props);
    this.simpleClass = Math.random().toString(36).substring(2);
    this.state = {
      isDrop: false,
      // eslint-disable-next-line react/no-unused-state
      offsetLeft: 0,
      // eslint-disable-next-line react/no-unused-state
      offsetTop: 0,
      realizeHeight: 0,
      modalHeight: 0,
    };
    this.deltaX = 0;
    this.deltaY = 0;
    this.contain = {};
    this.antModal = {};
  }

  // eslint-disable-next-line react/sort-comp
  handleMove = (event) => {
    if (this.state.isDrop) {
      this.antModal.style.margin = 0;
      this.antModal.style.padding = 0;
      const left = event.pageX - this.deltaX;
      const top = event.pageY - this.deltaY;
      // if (left < 0) {
      //   left = 0;
      // } else if (left > (document.offsetWidth - this.antModal.offsetWidth)) {
      //   left = document.offsetWidth - this.antModal.offsetWidth;
      // }
      // if (top < 0) {
      //   top = 0;
      // } else if (top > (document.offsetHeight - this.antModal.offsetHeight)) {
      //   top = document.offsetHeight - this.antModal.offsetHeight;
      // }
      this.antModal.style.left = `${left}px`;
      this.antModal.style.top = `${top}px`;
    }
  };

  addResizeListener = () => {
    document.addEventListener('mousedown', this.handleResize);
  }

  handleResize = (downEl) => {
    const ableList = ['resize-s', 'resize-sw', 'resize-se'];
    if (ableList.indexOf(downEl.target.className) === -1) {
      return;
    }
    // const modalContent = document.getElementsByClassName('ant-modal-content')[0];
    const modalContent = downEl.target.parentNode.parentNode;
    const modalContentHeight = modalContent.offsetHeight;
    if (!this.state.modalHeight) {
      this.setState({
        modalHeight: modalContentHeight,
      });
    }
    const modalContentWidth = modalContent.offsetWidth;
    const modalContentLeft = modalContent.offsetLeft;
    let resizedHeight = 0;
    let resizeYPx = 0;
    let resizeXPx = 0;
    document.onmousemove = (moveEvent) => {
      resizeYPx = moveEvent.pageY - downEl.pageY;
      resizeXPx = moveEvent.pageX - downEl.pageX;
      resizedHeight = this.state.modalHeight + this.state.realizeHeight + resizeYPx;
      if (resizedHeight <= this.state.modalHeight) {
        return false;
      }
      switch (downEl.target.className) {
        case 'resize-s':
          modalContent.style.height = `${resizedHeight}px`;
          break;
        case 'resize-sw':
          modalContent.style.height = `${resizedHeight}px`;
          modalContent.style.width = `${modalContentWidth - resizeXPx}px`;
          modalContent.style.left = `${modalContentLeft + resizeXPx}px`;
          break;
        case 'resize-se':
          modalContent.style.height = `${resizedHeight}px`;
          modalContent.style.width = `${modalContentWidth + resizeXPx}px`;
          break;
        default:
          break;
      }
    };
    document.onmouseup = () => {
      document.onmousemove = null;
      document.onmouseup = null;
      if (this.state.realizeHeight + resizeYPx <= 0 && this.props.onSaveState) {
        this.setState({
          realizeHeight: 0,
        });
        this.props.onSaveState({ realizeHeight: this.state.realizeHeight });
        return;
      }
      if (this.props.onSaveState && resizeYPx !== 0) {
        this.setState((prev) => {
          return {
            realizeHeight: prev.realizeHeight + resizeYPx,
          };
        });
        this.props.onSaveState({ realizeHeight: this.state.realizeHeight });
      }
    };
  }

  initialEvent = (visible) => {
    const { title } = this.props;
    if (title && visible) {
      setTimeout(() => {
        window.removeEventListener('mouseup', this.removeUp, false);
        // eslint-disable-next-line prefer-destructuring
        this.contain = document.getElementsByClassName(this.simpleClass)[0];
        // eslint-disable-next-line prefer-destructuring
        this.header = this.contain.getElementsByClassName('ant-modal-header')[0];
        this.header.style.cursor = 'all-scroll';
        // eslint-disable-next-line prefer-destructuring
        this.antModal = this.contain.getElementsByClassName('ant-modal')[0];
        this.header.onmousedown = (e) => {
          const disx = e.pageX - this.antModal.offsetLeft;
          const disy = e.pageY - this.antModal.offsetTop;
          this.deltaX = disx;
          this.deltaY = disy;
          this.setState({
            isDrop: true,
          });
          document.body.onselectstart = () => false;
          window.addEventListener('mousemove', this.handleMove.bind(this), false);
        };
        window.addEventListener('mouseup', this.removeUp, false);
        this.addResizeListener();
      }, 0);
    }
  };

  removeUp = () => {
    this.setState({ isDrop: false });
    document.body.onselectstart = () => true;
  };

  componentDidMount() {
    const { visible = false, open = false } = this.props;
    this.initialEvent(open || visible);
  }

  componentWillUnmount() {
    window.removeEventListener('mousedown', this.handleResize, false);
    window.removeEventListener('mouseup', this.removeUp, false);
    if (this.props.onSaveState) {
      this.props.onSaveState({ realizeHeight: 0 });
    }
  }

  render() {
    const {
      children, wrapClassName, pageLoading, forbidResize, ...other
    } = this.props;

    const wrapModalClassName = wrapClassName ? `${wrapClassName} ${this.simpleClass}` : `${this.simpleClass}`;
    return (
      <Modal
        {...other}
        maskClosable={false}
        keyboard
        wrapClassName={wrapModalClassName}
      >
        {children}
        {!forbidResize && <div className="resize-s" />}
        {!forbidResize && <div className="resize-sw" />}
        {!forbidResize && <div className="resize-se" />}
      </Modal>
    );
  }
}
export default AntDraggableModal;