序文ソースコードは合計で 100 行強しかありません。これを読めば、react-dnd などの成熟した react ドラッグ ライブラリの実装アイデアを大まかに理解でき、これらのライブラリをすぐに使い始めることができます。 フックを使用した場合の一般的な効果は次のとおりです。 私たちの目標は、useDrag フックと useDrop フックを実装することです。これにより、要素を簡単にドラッグ可能にすることができ、以下に示すように、ドラッグの各ライフサイクルでメッセージの配信をカスタマイズできます (ちなみに、ドラッグによってトリガーされるいくつかのイベントを導入します)。
使い方+ソースコード解説 クラスHelloはReact.Component<any, any>を拡張します。 コンストラクタ(props: any) { スーパー(小道具) this.state = {} } 与える() { 戻る ( <ドラッグアンドドロップ> <ドラッグ要素 /> <ドロップ要素 /> </ドラッグアンドドロップ> ) } } ReactDOM.render(<Hello />, window.document.getElementById("root")) 前述の通り、DragAndDrop コンポーネントの機能は、現在ドラッグされている要素がどの DOM であるかなどのメッセージを、useDrag と useDrop を使用するすべてのコンポーネントに渡すことですが、必要に応じて他の情報を追加することもできます。その実装を見てみましょう。 DragAndDropManager を React.createContext に追加します。 const DragAndDrop = ({ children }) => ( <DragAndDropContext.Provider 値 = {{ DragAndDropManager: new DragAndDropManager() }}> {子供たち} </ドラッグアンドドロップコンテキスト.プロバイダー> ) メッセージパッシングは react の Context API を使用して実装されていることがわかります。この DragAndDropManager に注目してください。実装を見てみましょう。 デフォルトクラスDragAndDropManagerをエクスポートします。 コンストラクタ() { this.active = null this.subscriptions = [] this.id = -1 } setActive(アクティブプロパティ) { this.active = アクティブプロパティ this.subscriptions.forEach((サブスクリプション) => subscription.callback()) } subscribe(コールバック) { this.id += 1 this.subscriptions.push({ 折り返し電話、 id: this.id, }) this.idを返す } 登録解除(id) { this.subscriptions = this.subscriptions.filter((sub) => sub.id !== id) } } setActive の機能は、現在ドラッグされている要素を記録することです。これは useDrag で使用されます。useDrag のフックの実装を見ると、setActive メソッドを呼び出してドラッグされた DOM 要素を渡すだけで、現在ドラッグされている要素がわかることがわかります。 さらに、イベントをサブスクライブするための API subscribe も追加しました。まだ使用していないため、この例では無視してかまいません。サブスクリプション イベントを追加できることだけ知っておいてください。 次に、useDrag の使い方を見てみましょう。DragElement の実装は次のとおりです。 関数DragElement() { 定数入力 = useRef(null) const hanleDrag = useDrag({ 参照: 入力、 collection: {}, // ここでドロップ要素に渡したいメッセージを入力できます。このメッセージは後でドロップ要素にパラメータとして渡されます}) 戻る ( <div ref={入力}> <h1 role="button" onClick={handleDrag}> ドラッグ要素 </div> ) } 非常にシンプルなuseDragの実装を見てみましょう。 デフォルト関数 useDrag(props) をエクスポートします。 const { DragAndDropManager } = useContext(DragAndDropContext) 定数handleDragStart = (e) => { DragAndDropManager.setActive(props.collection) e.dataTransfer !== 未定義の場合 { e.dataTransfer.effectAllowed = "移動" e.dataTransfer.dropEffect = "移動" e.dataTransfer.setData("text/plain", "drag") // Firefox の修正 } (props.onDragStart)の場合{ props.onDragStart(DragAndDropManager.active) } } 使用効果(() => { もしprops.refがそうであれば、戻り値は()=>{} 定数{ 参照: { 現在の }, } = 小道具 if (現在) { current.setAttribute("ドラッグ可能", true) current.addEventListener("dragstart", handleDragStart) } 戻り値 () => { current.removeEventListener("dragstart", handleDragStart) } }, [props.ref.current]) handleDragStart を返す } useDrag が行うことは非常にシンプルです。
このうち、useDrop の使用と DropElement の実装は次のとおりです。 関数 DropElement(props: any): any { 定数入力 = useRef(null) ドロップを使用します({ 参照: 入力、 // e は、dragOver イベントが発生したときにドラッグされている要素のイベント オブジェクトを表します // collection はストアに保存されているデータです // showAfter は、マウスが要素をドラッグしているときに、ドロップされた要素の上をマウスが通過するかどうかを示します (上は上半分、下は下半分) onDragOver: (e, コレクション, showAfter) => { // 上半分を通過すると、ドロップ要素の上部の境界線が赤くなります if (!showAfter) { input.current.style = "border-bottom: none;border-top: 1px の赤一色" } それ以外 { // 下半分を通過すると、ドロップ要素の上部の境界線は赤になります input.current.style = "border-top: none; border-bottom: 1px solid red" } }, // ドロップ要素上でマウスを離すと、スタイルがクリアされます onDrop: () => { 入力.現在のスタイル = "" }, // ドロップ要素を離れるとスタイルはクリアされます onDragLeave: () => { 入力.現在のスタイル = "" }, }) 戻る ( <div> <h1 ref={input}>要素をドロップ</h1> </div> ) } 最後に、useDropの実装を見てみましょう。 デフォルト関数 useDrop(props) をエクスポートします。 // 最も外側のストアのデータを取得します。const { DragAndDropManager } = useContext(DragAndDropContext) 定数handleDragOver = (e) => { // e はドラッグ イベント オブジェクトです e.preventDefault() // 下の getBoundingClientRect の図を参照してください const overElementHeight = e.currentTarget.getBoundingClientRect().height / 2 定数 overElementTopOffset = e.currentTarget.getBoundingClientRect().top // clientYはマウスからブラウザページの表示領域の上部までの距離です。const mousePositionY = e.clientY // mousePositionY - overElementTopOffset は、要素内のマウスから要素の border-top までの距離です。const showAfter = mousePositionY - overElementTopOffset > overElementHeight (props.onDragOver)の場合{ props.onDragOver(e, DragAndDropManager.active, showAfter) } } // ドロップイベント const handledDop = (e: React.DragEvent) => { e.preventDefault() (props.onDrop)の場合{ props.onDrop(DragAndDropManager.active) } } // dragLeave イベント const handlerragLeave = (e: React.DragEvent) => { e.preventDefault() (props.onDragLeave)の場合{ props.onDragLeave(DragAndDropManager.active) } } // イベントを登録します。メモリリークを避けるために、コンポーネントを破棄するときにはイベントの登録を解除する必要があることに注意してください。useEffect(() => { もしprops.refがそうであれば、戻り値は()=>{} 定数{ 参照: { 現在の }, } = 小道具 if (現在) { current.addEventListener("dragover", handleDragOver) current.addEventListener("ドロップ"、handledDop) current.addEventListener("dragleave", 処理済みragLeave) } 戻り値 () => { current.removeEventListener("dragover", handleDragOver) current.removeEventListener("drop", 処理されたDop) current.removeEventListener("dragleave", 処理済みragLeave) } }, [props.ref.current]) } GetBoundingClientRect API ダイアグラム: rectObject = object.getBoundingClientRect(); rectObject.top: 要素の上端からウィンドウの上端までの距離。 rectObject.right: 要素の右側からウィンドウの左側までの距離。 rectObject.bottom: 要素の下部からウィンドウの上部までの距離。 rectObject.left: 要素の左側からウィンドウの左側までの距離。 これで、100 行を超えるコードで React ドラッグ アンド ドロップ フックを実装する方法に関するこの記事は終了です。React ドラッグ アンド ドロップ フックに関するより関連性の高いコンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM を応援していただければ幸いです。 以下もご興味があるかもしれません:
|
<<: mysql5.7 でユーザーの初期パスワードを変更する方法
>>: Linux カーネル デバイス ドライバー システム コールに関する注意事項
なぜ Nexus プライベート サーバーを構築する必要があるのでしょうか。その理由は非常に簡単です。...
注意: 計画、設計、開発のいずれの場合でも、これらの間違いは避けなければなりません。 1. ナビゲー...
データ移行は、MySQL から ClickHouse にインポートする必要があります。概要プランは以...
この記事の例では、ネイティブJSカプセル化vueタブ切り替えの具体的なコードを参考までに共有していま...
Linux 操作実験環境: Centos7 仮想マシンまず、共通ユーザーgubeiqingを作成しま...
Nginx は現在、最も人気のあるロード バランサーの 1 つです。インターネット トラフィックの...
Tomcat を学習したばかりのプログラマーにとって、これはよくある間違いです。 1. 環境変数の問...
インターネット上で多くの関連チュートリアルを見てきましたが、インストール プロセスにはまだいくつかの...
簡単に言うと、distinct は重複を削除するために使用され、group by は統計を集計するよ...
ログインインターフェースの解像度が特に大きい場合、グラフィカルインターフェース全体が特に大きくなり、...
目次1. これは2. この点を修正する1. call() メソッド2. apply() メソッド要約...
目次前提TypeScript と JavaScriptコードエディタの選択TypeScriptを学ぶ...
まず、私たちがやりたいことは、serverA の usera を使用して、パスワードなしで serv...
私が学習していたときに使用していたバージョンは比較的新しいものであり、インターネット上のチュートリア...
目次1. 計画タスクをカスタマイズする2. 時間を同期する3. 練習する4. セキュリティの問題1....