react-beautiful-dnd を使用してリスト間のドラッグ アンド ドロップを実装する

react-beautiful-dnd を使用してリスト間のドラッグ アンド ドロップを実装する

react-beautiful-dndを選ぶ理由

react-dnd と比較すると、react-beautiful-dnd はリスト間のドラッグに適しており、モバイル端末をサポートし、使いやすいです。

基本的な使い方

基本概念

  • DragDropContext: ドラッグ可能な範囲を構築する
  • onDragStart: ドラッグ開始コールバック
  • onDragUpdate: ドラッグ中のコールバック
  • onDragEnd: ドラッグ終了時のコールバック
  • ドロップ可能 - ドラッグ可能なブロックを配置できる領域
  • ドラッグ可能な要素

使い方

ドラッグアンドドロップを可能にするコードをDragDropContextに記述します。

'react-beautiful-dnd' から {DragDropContext} をインポートします。

クラスAppはReact.Componentを拡張します。
  ドラッグ開始時 = () => {
    /*...*/
  };
  onDragUpdate = () => {
    /*...*/
  }
  ドラッグ終了時 = () => {
    // 唯一必要なのは
  };

  与える() {
    戻る (
      <ドラッグドロップコンテキスト
        onDragStart={this.onDragStart}
        onDragUpdate={this.onDragUpdate}
        onDragEnd={this.onDragEnd}
      >
        <div>こんにちは世界</div>
      </ドラッグドロップコンテキスト>
    );
  }
}

ドロップ可能な領域を決定する

'react-beautiful-dnd' から { DragDropContext, Droppable } をインポートします。

クラスAppはReact.Componentを拡張します。
  // ...
  与える() {
    戻る (
      <ドラッグドロップコンテキスト
        onDragStart={this.onDragStart}
        onDragUpdate={this.onDragUpdate}
        onDragEnd={this.onDragEnd}
      >
        <ドロップ可能 droppableId="droppable-1">
          {(提供、スナップショット) => (
            <div
              ref={provided.innerRef}
              style={{ backgroundColor: snapshot.isDraggingOver ? 'blue' : 'grey' }}
              {...提供されたドロップ可能なプロパティ}
            >
              <h2>私は落とされる存在です!</h2>
              {提供されたプレースホルダー}
            </div>
          )}
        </ドロップ可能>
      </ドラッグドロップコンテキスト>
    );
  }
}
  • アプリケーションのドロップ可能なものを一意に識別する必須の DroppableId (文字列)。特にドラッグ中は、このIDを変更しないでください。
  • provided.placeholder: プレースホルダー (このプレースホルダーはデフォルトであり、通常は要件を満たしません)
  • スナップショット: 現在のドラッグ状態。ドラッグ中にドロップ可能なオブジェクトの外観を変更するために使用できます。

Draggableを使用して、ドラッグ要素をドロップ可能領域にラップします。

'react-beautiful-dnd' から { DragDropContext、Droppable、Draggable } をインポートします。

クラスAppはReact.Componentを拡張します。
  // ...

  与える() {
    戻る (
      <ドラッグドロップコンテキスト
        onDragStart={this.onDragStart}
        onDragUpdate={this.onDragUpdate}
        onDragEnd={this.onDragEnd}
      >
        <ドロップ可能 droppableId="droppable-1">
          {(提供、スナップショット) => (
            <div
              ref={provided.innerRef}
              style={{ backgroundColor: snapshot.isDraggingOver ? 'blue' : 'grey' }}
              {...提供されたドロップ可能なプロパティ}
            >
              <ドラッグ可能 draggableId="draggable-1" index={0}>
                {(提供、スナップショット) => (
                    <div
                      ref={provided.innerRef}
                      {...提供されるドラッグ可能なプロパティ}
                      {...提供されるdragHandleProps}
                    >
                      <h4>ドラッグ可能なもの</h4>
                    </div>
                )}
              </ドラッグ可能>
              {提供されたプレースホルダー}
            </div>
          )}
        </ドロップ可能>
      </ドラッグドロップコンテキスト>
    );
  }
}
  • ドラッグ可能なオブジェクトは常にドロップ可能なオブジェクト内に含まれている必要があります
  • DraggablebId (文字列): 一意の ID とインデックス (トラバーサル キーの場合はこれも必要) が存在する必要があります。特にドラッグ中は、この ID を変更しないでください。

ドラッグが終了したら、ソースデータを変更します

onDragEnd = 結果 => {
  const { ソース、 宛先、 ドラッグ可能な ID } = 結果;
  if (!destination) {
    戻る;
  }

  // ソース配列とターゲット配列を変更し、ドラッグした要素をソース配列から削除して、ターゲット配列に挿入します this.setState({
    xxx: xxx、
  });
}

使用中に発生した問題

ドラッグターゲット領域にカスタムプレースホルダーを追加する

react-beautiful-dnd がターゲット領域にドラッグされると、現在のドラッグ要素に対して、ターゲット領域内の要素間にスペースが自動的に確保されます。このスペースの距離は、ターゲット領域内のドラッグ可能な要素のサイズです (ただし、要素のマージンは含まれません。これも落とし穴です。解決策については後述します)。

したがって、この距離内で絶対配置を使用し、カスタム プレースホルダーを追加できます。具体的なアプローチ: 現在のカスタム プレースホルダー要素の左と上の距離を計算し、dragUpdate イベントでこの 2 つの距離を更新します。beatiful-dnd-custom-placeholder-demo を参照してください。

ドラッグ時に、ドラッグされた要素の変換プロパティを変更すると、ドラッグがどこかで停止し、ドラッグされた要素が間違った位置に配置されます。

公式ドキュメントには、ドラッグ可能な要素は position: fixed 配置を使用するが、transform の影響を受けるという大まかな説明があります。

#### 警告: `position: fixed`

`react-beautiful-dnd` は、ドラッグ要素の位置を決めるために `position: fixed` を使用します。これは非常に堅牢で、`position: relative | absolute | fixed` の親を持つことができます。しかし、残念ながら `position:fixed` は [`transform` の影響を受けます](http://meyerweb.com/eric/thoughts/2011/09/12/un-fixing-fixed-elements-with-css-transforms/) (`transform: rotate(10deg);` など)。つまり、`<Draggable />` の親の 1 つに `transform: *` があると、ドラッグ中に位置を決めるロジックが間違ってしまいます。残念です! ほとんどの消費者にとって、これは問題にはなりません。

この問題を回避するには、[<Draggable /> の親を変更する](/docs/guides/reparenting.md) ことができます。パフォーマンス上の問題があるため、この機能はデフォルトでは有効になっていません。

次の解決策が提供されています: createPortal を使用して、ドラッグ要素を空の親要素に掛けます。問題を参照してください: 親の変換によりドラッグの配置が混乱します

しかし、この方法では問題は解決されません。カスタム プレースホルダーがまだ必要だからです。ドラッグ時には、プレースホルダーの左距離も計算する必要があり、これは、現在ドラッグされている要素の parentNode の下にある子要素を取得する必要があることを意味します。createPortal を使用すると、ドラッグされている要素の元の parentNode を取得できないため、createPortal ソリューションは放棄されます。 transform: scale の効果は、幅と高さを変更することによって実現されます。

モバイルで要素をドラッグするには、長押しする必要があります。

公式ドキュメントには、モバイル シナリオでは、ドラッグ可能な要素に対する指の操作がタップ、強制押し、スクロールのいずれであるかを判断できないため、ドラッグかどうかを判断するには要素を長押しする必要がある、と記載されています。

ドラッグの開始: 長押し
ユーザーは、指👇を要素の上で短時間🕑(長押し)押し続けることでドラッグを開始できます。

要素をドラッグして目的の位置にホバーすると、空いた挿入スペースの距離が不正確になります。これが上記の問題です。ドラッグ可能要素間に残されたプレースホルダーの自由距離はドラッグ可能要素の距離ですが、ドラッグ可能要素の余白は含まれません。この問題を参照してください。

最後に、ドラッグ中に空いたスペースにパディングが含まれるように、パディングを使用してドラッグ可能要素間の距離を制御します。

要約する

react-beautiful-dnd は比較的使いやすいです。2021年3月現在、v13.1.0 がリリースされており、比較的活発に動いています。上記の落とし穴が皆様のお役に立てれば幸いです。

参考文献

公式サイト beautiful-dnd
react-beautiful-dnd 入門チュートリアル

react-beautiful-dnd を使用してリスト間のドラッグ アンド ドロップを実装する方法についての説明はこれで終わりです。さらに関連性の高い react リスト ドラッグ アンド ドロップ コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • ドラッグ可能で編集可能なガントチャートの詳細な説明(HighchartsはVueとReactで使用できます)
  • Typescript+React でモバイルと PC でシンプルなドラッグ アンド ドロップ効果を実現
  • react-beautiful-dnd はコンポーネントのドラッグ アンド ドロップ機能を実装します
  • Reactドラッグフックを実装するための100行以上のコード
  • React.js コンポーネントはドラッグ アンド ドロップによるソート コンポーネント機能のプロセス分析を実装します
  • ドラッグアンドドロップ機能を実装するReactサンプルコード
  • React.js コンポーネントはドラッグ アンド ドロップ コピーとソート可能なサンプル コードを実装します
  • React.jsがネイティブjsドラッグエフェクトを実装することで発生する一連の問題についてもう一度話しましょう
  • React.js をベースにしたネイティブ js ドラッグ エフェクトの実装に関する考察
  • Reactはシンプルなドラッグアンドドロップ機能を実装します

<<:  Linux 環境での Oracle 導入チュートリアル

>>:  Windows オペレーティング システムでポートの使用状況を照会およびクリアするプログラム

推薦する

HTML CSS に基づく検索アイコン付き検索ボックス機能を実装する

序文フロントエンドで非常に便利な、小さなアイコン付きの検索ボックスを作成する方法をご紹介します。エフ...

CSS3 アニメーション ボールローリング JS コントロールアニメーション一時停止

CSS3 はアニメーションを作成でき、多くの Web ページのアニメーション画像、Flash アニメ...

Vueリストデータを削除した後、ページを自動的に更新する方法と更新方法の詳細な説明

問題の説明:フロントエンドがデータの一部を削除したり、新しいデータを追加したりすると、バックエンドの...

ノードイベントループにおけるイベント実行の順序

目次イベントループブラウザ環境イベントループノード環境イベントループ6つのステージ(1)setTim...

同じ日の最初の3つのデータを取得するためのMySQLタイムラインデータ

テーブルデータを作成する テーブル `praise_info` を作成します ( `id` bigi...

Windowsにmysql5.7をインストールする方法

まずmysqlの圧縮バージョンをダウンロードします。公式ダウンロードアドレスは123WORDPRES...

Vue3 親子コンポーネントパラメータ転送における sync 修飾子の使用法の詳細な説明

目次一方向データフローの説明Vue2.x の使用法親コンポーネントに変更を通知するイベントのフォーム...

Linux 環境の Apache サーバーでセカンダリドメイン名を設定する方法の詳細な説明

この記事では、Linux 環境の Apache サーバーでセカンダリ ドメイン名を構成する方法につい...

トップに戻るボタンを実装するJavaScript

この記事では、トップに戻るボタンを実装するためのJavaScriptの具体的なコードを参考までに紹介...

Javascript で関数のカリー化とデカリー化を実装する方法

関数のカリー化(黒い疑問符の顔)? ? ?カレー(黒い疑問符の顔)? ? ?これは完璧な中国語翻訳で...

TypeScript 名前空間のマージの説明

目次同じ名前の名前空間をマージする名前空間とその他の種類のマージ同じ名前の名前空間とクラスをマージす...

HTML でマウスが停止したときに行全体の色 (tr) を変更する方法

純粋な CSS を使用して、マウスが行の上を通過するときに行の背景色を変更し、その行にフォーカスがあ...

JS 9 Promise 面接の質問

目次1. 複数の .catch 2. 複数の .catch 3. .then と .catch の連...

MySQL inndbジョイントインデックスを正しく使用する方法を徹底的に理解するためのケーススタディ

最近確認された5件のデータを照会するビジネスがあります。 `id`、`title` を選択 `th_...

ウェブデザイン必携ハンドブック 216 ウェブセーフカラー

Web ページ上の色の表現は、さまざまな要因によって影響を受けます。Web ページで非常に美しい配色...