ドラッグアンドドロップによる並べ替えの詳細を実現する js

ドラッグアンドドロップによる並べ替えの詳細を実現する js

1. はじめに

ドラッグ アンド ドロップによる並べ替えは、誰にとっても馴染みのある操作です。通常の作業では、ニーズに合わせてSortable.jsなどのオープン ソース ライブラリを使用することもできます。しかし、要件を満たした後、ドラッグ アンド ドロップによる並べ替えを実現する方法について考えたことはありますか?私は時間をかけて調査し、今日それを皆さんと共有します。

2. 実装

 {
    マージン: 0;
    パディング: 0;
    ボックスのサイズ: 境界線ボックス;
}

.グリッド{
    ディスプレイ: フレックス;
    flex-wrap: ラップ;
    マージン: 0 -15px -15px 0;
    タッチアクション: なし;
    ユーザー選択: なし;
}

.グリッドアイテム{
    幅: 90ピクセル;
    高さ: 90px;
    行の高さ: 88px;
    テキスト配置: 中央;
    マージン: 0 15px 15px 0;
    背景: #FFF;
    境界線: 1px 実線 #d6d6d6;
    リストスタイル: なし;
}

。アクティブ {
    背景: #c8ebfb;
}

.clone-grid-item {
    位置: 固定;
    左: 0;
    上: 0;
    zインデックス: 1;
    幅: 90ピクセル;
    高さ: 90px;
    行の高さ: 88px;
    テキスト配置: 中央;
    背景: #FFF;
    境界線: 1px 実線 #d6d6d6;
    不透明度: 0.8;
    リストスタイル: なし;
}

<ul class="grid">
    <li class="grid-item">項目1</li>
    <li class="grid-item">項目2</li>
    <li class="grid-item">項目3</li>
    <li class="grid-item">項目4</li>
    <li class="grid-item">項目5</li>
    <li class="grid-item">項目6</li>
    <li class="grid-item">項目7</li>
    <li class="grid-item">項目8</li>
    <li class="grid-item">項目9</li>
    <li class="grid-item">アイテム10</li>
</ul>

ES6 クラスの記述を使用する:

クラス Draggable {
    コンストラクタ(オプション) {
        this.parent = options.element; // 親要素 this.cloneElementClassName = options.cloneElementClassName; // 複製要素のクラス名 this.isPointerdown = false;
        this.diff = { x: 0, y: 0 }; // 最後の移動に対する差異 this.drag = { element: null, index: 0, lastIndex: 0 }; // 要素をドラッグ this.drop = { element: null, index: 0, lastIndex: 0 }; // 要素を解放 this.clone = { element: null, x: 0, y: 0 };
        this.lastPointermove = { x: 0, y: 0 };
        this.rectList = []; // ドラッグアイテムのgetBoundingClientRect()メソッドによって取得されたデータを保存するために使用されます。this.init();
    }
    初期化() {
        this.getRect();
        このイベントリスナーをバインドします。
    }
    // 要素の位置情報を取得する getRect() {
        this.rectList.length = 0;
        for (this.parent.children の定数項目) {
            this.rectList.push(item.getBoundingClientRect());
        }
    }
    ハンドルポインタダウン(e) {
        // マウスクリックの場合は左ボタンにのみ反応します if (e.pointerType === 'mouse' && e.button !== 0) {
            戻る;
        }
        if (e.target === this.parent) {
            戻る;
        }
        this.isPointerdown = true;
        this.parent.setPointerCapture(e.pointerId);
        this.lastPointermove.x = e.clientX;
        this.lastPointermove.y = e.clientY;
        this.drag.element = e.target;
        this.drag.element.classList.add('active');
        this.clone.element = this.drag.element.cloneNode(true);
        this.clone.element.className = this.cloneElementClassName;
        this.clone.element.style.transition = 'なし';
        const i = [].indexOf.call(this.parent.children, this.drag.element);
        this.clone.x = this.rectList[i].left;
        this.clone.y = this.rectList[i].top;
        this.drag.index = i;
        this.drag.lastIndex = i;
        this.clone.element.style.transform = 'translate3d(' + this.clone.x + 'px, ' + this.clone.y + 'px, 0)';
        document.body.appendChild(this.clone.element);
    }
    ハンドルポインタ移動(e) {
        if (this.isPointerdown) {
            this.diff.x = e.clientX - this.lastPointermove.x;
            this.diff.y = e.clientY - this.lastPointermove.y;
            this.lastPointermove.x = e.clientX;
            this.lastPointermove.y = e.clientY;
            this.clone.x += this.diff.x;
            this.clone.y += this.diff.y;
            this.clone.element.style.transform = 'translate3d(' + this.clone.x + 'px, ' + this.clone.y + 'px, 0)';
            (i = 0 とします; i < this.rectList.length; i++) {
                // 衝突検出 if (e.clientX > this.rectList[i].left && e.clientX < this.rectList[i].right &&
                    e.clientY > this.rectList[i].top && e.clientY < this.rectList[i].bottom) {
                    this.drop.element = this.parent.children[i];
                    this.drop.lastIndex = i;
                    if (this.drag.element !== this.drop.element) {
                        if (this.drag.index < i) {
                            this.parent.insertBefore(this.drag.element、this.drop.element.nextElementSibling);
                            this.drop.index = i - 1;
                        } それ以外 {
                            this.parent.insertBefore(this.drag.element、this.drop.element);
                            this.drop.index = i + 1;
                        }
                        this.drag.index = i;
                        定数dragRect = this.rectList[this.drag.index];
                        定数 lastDragRect = this.rectList[this.drag.lastIndex];
                        定数 dropRect = this.rectList[this.drop.index];
                        定数 lastDropRect = this.rectList[this.drop.lastIndex];
                        this.drag.lastIndex = i;
                        this.drag.element.style.transition = 'なし';
                        this.drop.element.style.transition = 'なし';
                        this.drag.element.style.transform = 'translate3d(' + (lastDragRect.left - dragRect.left) + 'px, ' + (lastDragRect.top - dragRect.top) + 'px, 0)';
                        this.drop.element.style.transform = 'translate3d(' + (lastDropRect.left - dropRect.left) + 'px, ' + (lastDropRect.top - dropRect.top) + 'px, 0)';
                        this.drag.element.offsetLeft; // 再描画をトリガーします this.drag.element.style.transition = 'transform 150ms';
                        this.drop.element.style.transition = '150ms で変換';
                        this.drag.element.style.transform = 'translate3d(0px, 0px, 0px)';
                        this.drop.element.style.transform = 'translate3d(0px, 0px, 0px)';
                    }
                    壊す;
                }
            }
        }
    }
    ハンドルポインタアップ(e) {
        if (this.isPointerdown) {
            this.isPointerdown = false;
            this.drag.element.classList.remove('active');
            this.clone.element.remove();
        }
    }
    ハンドルポインタキャンセル(e) {
        if (this.isPointerdown) {
            this.isPointerdown = false;
            this.drag.element.classList.remove('active');
            this.clone.element.remove();
        }
    }
    バインドイベントリスナー() {
        this.handlePointerdown = this.handlePointerdown.bind(this);
        this.handlePointermove = this.handlePointermove.bind(this);
        this.handlePointerup = this.handlePointerup.bind(this);
        this.handlePointercancel = this.handlePointercancel.bind(this);
        this.getRect = this.getRect.bind(this);
        this.parent.addEventListener('pointerdown', this.handlePointerdown);
        this.parent.addEventListener('pointermove', this.handlePointermove);
        this.parent.addEventListener('pointerup', this.handlePointerup);
        this.parent.addEventListener('pointercancel', this.handlePointercancel);
        window.addEventListener('スクロール'、this.getRect);
        window.addEventListener('resize', this.getRect);
        window.addEventListener('orientationchange', this.getRect);
    }
    アンバインドイベントリスナー() {
        this.parent.removeEventListener('pointerdown', this.handlePointerdown);
        this.parent.removeEventListener('pointermove', this.handlePointermove);
        this.parent.removeEventListener('pointerup', this.handlePointerup);
        this.parent.removeEventListener('pointercancel', this.handlePointercancel);
        window.removeEventListener('scroll', this.getRect);
        ウィンドウのサイズ変更イベント リスナーを削除します。
        window.removeEventListener('orientationchange', this.getRect);
    }
}
// 新しい Draggable をインスタンス化します({
    要素: document.querySelector('.grid'),
    cloneElementClassName: 'clone-grid-item'
});

デモ: jsdemo.codeman.top/html/dragga…

3. HTML ドラッグ アンド ドロップ API を使用しないのはなぜですか?

ネイティブHTMLドラッグ アンド ドロップAPIモバイル デバイスでは使用できないため、 PCとモバイル デバイスの両方と互換性を持たせるために、 PointerEventイベントを使用してドラッグ ロジックを実装します。

4. まとめ

ドラッグアンドドロップによる並べ替えの基本機能は実装されていますが、まだ欠点が多くあります。ネストされたドラッグ、リスト間でのドラッグ、一番下までドラッグしたときの自動スクロールなどの機能は実装されていません。

ドラッグアンドドロップソートをjsで実装する詳細に関するこの記事はこれで終わりです。ドラッグアンドドロップソートをjsで実装することに関するより関連性の高いコンテンツについては、123WORDPRESS.COMで以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも123WORDPRESS.COMをよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Antdesign-vueとsortablejsを組み合わせて、2つのテーブルをドラッグして並べ替える機能を実現
  • js に基づく画像のドラッグ アンド ドロップによる並べ替えのソース コード例
  • React.js コンポーネントはドラッグ アンド ドロップによるソート コンポーネント機能のプロセス分析を実装します
  • Elementui テーブル コンポーネント + sortablejs を使用して行のドラッグ アンド ドロップによる並べ替えを実装するサンプル コード
  • AngularJS ドラッグ アンド ドロップ プラグイン ngDraggable.js をベースにしたドラッグ アンド ドロップ ソートの実装
  • JS ドラッグアンドドロップソートプラグイン Sortable.js の使用例分析
  • React.js コンポーネントはドラッグ アンド ドロップ コピーとソート可能なサンプル コードを実装します
  • JS は、シンプルな画像のドラッグ アンド ドロップによる並べ替えのサンプル コードを実装します。

<<:  ウェブデザインにおける円形要素の使用例 25 選

>>:  MySQL Shellの紹介とインストール

推薦する

Dockerデータのバックアップとリカバリプロセスの詳細な説明

データのバックアップ操作は非常に簡単です。次のコマンドを実行します。 docker run --vo...

MySQL でのストアド プロシージャと関数の作成の詳細な説明

目次1. ストアドプロシージャ1.1. 基本構文1.2 実行権限を指定してストアドプロシージャを作成...

Vue3 の父子値転送に関する簡単な説明

目次父から息子へ: 1. 親コンポーネントのサブコンポーネントタグに、サブコンポーネントに渡されるデ...

キーフリーログインプロセスを実現するためのLinux構成の分析

1.sshコマンドLinux では、ssh コマンドを使用して別のサーバーにログインできます。 2 ...

ドキュメントの場所の比較

<br />2 年前に PPK が投稿した素晴らしいブログ記事では、contains()...

Vueスロットの実装原理についての簡単な説明

目次1. サンプルコード2. 現象を通して本質を見抜く3. 実施原則4. 親コンポーネントのコンパイ...

React の 3 つの主要属性における Ref の使用に関する詳細な説明

目次クラスコンポーネント機能コンポーネントインタビューのよくある質問: React における ref...

Centos7でのSambaサーバー構成(実戦)

サンバの概要Samba は、Linux および UNIX システム上で SMB プロトコルを実装する...

Zookeeperスタンドアロン環境とクラスタ環境の構築

1. 単一マシン環境の構築# 1.1 ダウンロードZookeeper の対応するバージョンをダウンロ...

MySQL の分離レベルの包括的な分析

データベースが同じデータ バッチを同時に追加、削除、および変更すると、ダーティ書き込み、ダーティ読み...

CSS でハートを描く 3 つの方法

以下では、CSS を使用してハートの形を描く 3 つの方法を紹介します。実装プロセスは非常にシンプル...

Zabbix による VMware Exsi ホストの監視のグラフィカルな手順

1. 仮想化 vcenter に入り、ブラウザでログインし (クライアントは設定する場所を見つけませ...

HTMLインライン要素とブロックレベル要素の基本概念と使用例

HTML タグには、インライン要素とブロックレベル要素の 2 種類があります。まず、インライン要素と...

Windows で削除された MySQL 8.0.17 のルート アカウントとパスワードを回復する方法

少し前にSQLの独学を終え、MySQL 8.0.17をダウンロードしました。インストールして設定した...