ドラッグアンドドロップによる並べ替えの詳細を実現する 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の紹介とインストール

推薦する

表 td 画像水平および垂直中央揃えコード

HTMLコード:コードをコピーコードは次のとおりです。 <td align="cen...

CSSは高さを設定せずにdivを完全に中央に配置することを実現します

必要とする本文の下のdivは垂直方向に中央揃えになっていますdiv 内のテキストを垂直中央に配置する...

ドメイン名を nginx サービスにバインドする方法

nginx.conf で複数のサーバーを設定します。 http リクエストを処理する際、nginx ...

Vue ボタンの権限制御の導入

目次1. 手順1. ボタンの権限を定義する2. ストアを定義する3. 権限指示を作成する4. パーミ...

MySQL ページング中にオフセットが大きすぎる場合の SQL 最適化の経験の共有

問題を見つけるコンテンツをリストで表示すると、リスト内のコンテンツの数は多いかもしれませんが、ユーザ...

HTML ウェブページでのアンカー(名前付きアンカー)の使用の概要

以下の情報はインターネットから収集したものです1. アンカーは、Web ページ作成におけるハイパーリ...

HTML は Double 11 クーポン取得を実装します (クーポン取得ページを開く時間を設定します)

さっそく、コードを直接投稿します。具体的なコードは次のとおりです。 <!DOCTYPE htm...

Vueメソッドに基づくシンプルなタイマーの実装

Vueのシンプルなタイマーを参考にしてください。具体的な内容は以下のとおりです原理: setInte...

Win10 での MySQL 8.0 ログインでユーザー 'root'@'localhost' のアクセスが拒否される (パスワード使用: YES) 問題の解決方法

最近、MySQL を学び始めました。インストールはスムーズに進み、インターネット上の既成のチュートリ...

Linux sedコマンドの使用

1. 機能紹介sed (Stream EDitor) は、コンテンツを 1 行ずつ処理するストリーム...

MySQL 外部キー制約とテーブル関係の概要

目次外部キーテーブルの関係を決定する方法テーブル関係を作成する方法1対多の関係 - 従業員テーブルと...

MYSQL における char と varchar の違い

CHAR 型と VARCHAR 型は似ていますが、主に格納場所、末尾のスペース、取得方法が異なります...

HTML マウス CSS コントロール

一般的に、マウスは上向きの斜め矢印として表示され、テキストの上に移動すると垂直線になり、ハイパーリン...

発生したブラウザの互換性の問題と解決策(推奨)について

序文:先週の日曜日、先輩から3ページ作るのを手伝って欲しいと頼まれました。データのやり取りなどはなく...