モーダルボックスをreactでドラッグアンドドロップする方法

序文

実際の開発では、モーダルボックスの表示データが表示されることがよくありますが、残念ながら、関数の開発後、UIの学生が突然モーダルボックスをドラッグするように要求することがあります。この記事で使用するモーダルボックスは、のモーダルコンポーネントによってカプセル化されています。 ant design 3.0はい、元のコードを変更せずにドラッグアンドドロップを実装する方法。最終的なレンダリングは次のとおりです。

ここに画像の説明を挿入します

練習

1.高次コンポーネントDragHocを作成します

新しいファイルModalDrag / index.jsを作成し、次のコードをそのファイルにコピーします

DragObjは、特定のドラッグアンドドロップ用のネイティブjsコードです。後で参照してください。

  • DragHocは、高次コンポーネントを作成する関数です。ここで、パラメーターInnerComponentは変換する必要のあるモーダルコンポーネントであり、関数の最終的な戻り値は拡張コンポーネントです。

  • renderメソッドは<InnerComponent />を直接返し、新しいコンポーネントは返しません。高レベルコンポーネント全体の役割は、入力コンポーネントにref属性を追加することです。refを使用すると、initメソッドはReactDOMを介して取得できます。 findDOMNode。インポートするコンポーネントのネイティブdom。domを取得したら、基になるdom操作またはイベントバインディングを実行して、ドラッグアンドドロップを実現できます。

  • 遅延が0のタイマーがinitメソッドに追加されます。作成者のプロジェクトのInnerComponentがantデザインのModalでカプセル化されているためです。デバッグプロセス中に、ReactDOM.findDOMNodeはマウントされているdomのみを返すことができることがわかりました。ページ。要素、それ以外の場合はnullを返します。また、antデザインのモーダルレンダリングコンテンツは非同期であるため、タイマーを使用して次のフレームまで待機し、findDOMNodeを使用してコンポーネントのdom要素を取得する必要があります。非同期レンダリングコードが含まれていない場合、次のタイマーは削除できます

  • コンポーネントがアンインストールされたときにdestroyメソッドを呼び出して、バインドされたすべてのイベントを解放します

要素をドラッグするには、通常2つのパラメーターを渡す必要があります。1つはプッシュ後に移動できる領域で、上の図のエクスポートされたテーブルコントロール全体に対応し、コントロールのクラス名はmain_classです。もう1つは領域です。ドラッグを監視します。上の図のヘッドでは、ヘッドが押されたときにマウスを動かした場合にのみテーブルをドラッグできます。ヘッドのクラス名はtitle_classです。両方のパラメータは外部から渡されます。どちらのパラメーターも渡されません。デフォルトでは、child_nodeを直接監視し、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" />;
    }
  };


ドラッグが実際には無効であることがわかった場合は、上記のコードでchild_nodeを出力して、実際のdomを取得したかどうか、および完全にレンダリングされているかどうかを確認してください。完全にレンダリングされていない場合は、InnerComponentに次のものが含まれていることを意味します。非同期レンダリングコード。ドラッグアンドドロップイベントのバインドが完了したら、レンダリングするまで待つ必要があります。


2.ドラッグアンドドロップクラスDragObjを作成します

新しいファイルModalDrag / drag.jsを作成し、次のコードをそのファイルにコピーします

以下は、ドラッグアンドドロップを実装するためのネイティブコードです。これは主に、イベントのバインドとdom要素の位置の変更を担当します。

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.外線通話

高階関数DragHocを導入し、拡張が必要な​​モーダルコンポーネントToastExportを導入します

作成者はプロジェクトのモーダルボックスとしてantdesign 3.0のモーダルコンポーネントを使用しているため、ドラッグするだけでクラス名「ant-modal-content」と「ant-modal-header」を渡す必要があります。

他のシナリオでは、静的モーダルボックスコンポーネントのdom構造に従って移動するパーツ、監視およびドラッグするパーツを分析する必要があり、これら2つのパーツのクラス名がパラメーターとして渡されます。


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

DragHoc関数を呼び出してToastExportv2を生成した後、ページで直接使用できます。ビジネスでパラメーターを渡す必要がある場合は、パラメーターを属性に直接追加します。


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

呼び出すときは、イベントがバインドされたときにdomがレンダリングされないようにするために、visibleがtrueのときにToastExportv2をレンダリングすることに注意する必要があります。visibleがfalseの場合、コンポーネントの破棄は自動的にdestroyメソッドを呼び出して登録済みのバインドを解除しますイベント

おすすめ

転載: blog.csdn.net/brokenkay/article/details/109229686
おすすめ