JavaScript オブジェクト指向の実践の詳細説明: カプセル化とオブジェクトのドラッグ

JavaScript オブジェクト指向の実践の詳細説明: カプセル化とオブジェクトのドラッグ

概要

より多くの方法を理解し、比較できるようにするために、ドラッグを実装するために 3 つの異なる方法を使用します。

  • オブジェクトをカプセル化せずに直接実装します。
  • ネイティブ JavaScript を使用してドラッグ オブジェクトをカプセル化します。
  • jQuery を拡張してオブジェクトのドラッグを実装します。

ドラッグアンドドロップの実装プロセスには、多くの実用的な知識が含まれます。そのため、私自身の知識の蓄積を強化し、皆さんにさらに多くの知識を学んでもらうために、いくつかの詳細を詳しく共有したいと思います。注意深く読めば、必ず何かを学べると信じています。

1. DOM要素をアニメーション化する方法

多くの場合、要素の top、left、translate を変更して要素の位置を変更します。以下の例では、ボタンがクリックされるたびに、対応する要素が 5 ピクセル移動します。ここをクリックしてご覧ください。

クリックすると、要素をアニメーション化する小さな例が表示されます。

要素の top/left の値を変更するとページが再描画されますが、translate では再描画されないため、パフォーマンス最適化の観点から、translate 属性の使用を優先します。

2. 現在のブラウザでサポートされている変換互換の書き込み方法を取得する方法

Transform は CSS3 属性であり、これを使用する場合は互換性の問題に直面します。異なるブラウザの互換性のあるバージョンを記述する方法は、おおよそ次のとおりです。

['transform'、'webkitTransform'、'MozTransform'、'msTransform'、'OTransform']

したがって、現在のブラウザ環境でどの変換属性がサポートされているかを判断する必要があります。方法は次のとおりです。

// 現在のブラウザでサポートされている変換互換の書き込みメソッドを取得する関数 getTransform() {
    var 変換 = ''、
    divStyle = document.createElement('div').style,
    // 互換性のある書き込み方法が複数ある場合があり、ブラウザが認識するものはループを通じて見つけられます。 transformArr = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'OTransform'],

    i = 0,
    len = transformArr.length;

    for(; i < len; i++) {
        if (transformArr[i] が divStyle にある) {
            // 見つけたらすぐに戻り、関数を終了します。 return transform = transformArr[i];
        }
    }

    // 見つからない場合は、空の文字列を返します。 return transform;
}

このメソッドは、ブラウザでサポートされている変換プロパティを取得するために使用されます。空の文字列が返された場合は、現在のブラウザが transform をサポートしていないことを意味します。このとき、要素の位置を変更するには、left と top の値を使用する必要があります。サポートされている場合は、transform の値を変更します。

3. 要素の初期位置を取得する方法

まず、ターゲット要素の初期位置を取得する必要があるため、ここでは要素のスタイルを取得するために特別に使用される関数が必要です。

ただし、IE で要素スタイルを取得する方法は他のブラウザとは少し異なるため、互換性のある記述方法が必要です。

関数 getStyle(要素, プロパティ) {
    // つまり、要素のスタイルを取得するために currentStyle を使用し、他のブラウザは getComputedStyle を使用して取得します。 return document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(elem, false)[property] : elem.currentStyle[property];
}

このメソッドを使用すると、ターゲット要素の初期位置を取得するメソッドの記述を開始できます。

関数 getTargetPos(要素) {
    var pos = {x: 0, y: 0};
    var transform = getTransform();
    if(変換) {
        var transformValue = getStyle(elem, transform);
        if(変換値 == 'なし') {
            elem.style[transform] = 'translate(0, 0)';
            位置を返します。
        } それ以外 {
            var temp = transformValue.match(/-?\d+/g);
            戻り値 pos = {
                x: parseInt(temp[4].trim())、
                y: parseInt(temp[5].trim())
            }
        }
    } それ以外 {
        if(getStyle(elem, 'position') == 'static') {
            elem.style.position = '相対';
            位置を返します。
        } それ以外 {
            var x = parseInt(getStyle(elem, 'left') ? getStyle(elem, 'left') : 0);
            var y = parseInt(getStyle(elem, 'top') ? getStyle(elem, 'top') : 0);
            戻り値 pos = {
                x: x,
                y: y
            }
        }
    }
}

ドラッグ処理中は、ターゲット要素が移動できるようにその新しい位置を常に設定する必要があるため、ターゲット要素の位置を設定するメソッドが必要です。

// 位置 = { x: 200, y: 100 }
関数setTargetPos(要素, pos) {
    var transform = getTransform();
    if(変換) {
        elem.style[transform] = 'translate('+ pos.x +'px, '+ pos.y +'px)';
    } それ以外 {
        elem.style.left = pos.x + 'px';
        elem.style.top = pos.y + 'px';
    }
    要素を返します。
}

5. どのようなイベントを使用する必要がありますか?

PC のブラウザでは、mousedown、mousemove、mouseup の 3 つのイベントを組み合わせることでドラッグを実現できます。

  • mousedown マウスが押されたときにトリガーされます
  • mousemoveはマウスが押されてドラッグされたときにトリガーされます
  • mouseup マウスが離されたときにトリガーされます

モバイル側では、それぞれ touchstart、touchmove、touchend が対応します。

これらのイベントを要素にバインドすると、イベント オブジェクトがパラメーターとしてコールバック関数に渡されます。イベント オブジェクトを通じて、現在のマウスの正確な位置を取得できます。マウスの位置情報こそが、ドラッグを実現するための鍵となります。

イベント オブジェクトは非常に重要で、多くの有用な情報が含まれています。ここでは詳しく説明しません。関数内でイベント オブジェクトを出力して、その特定のプロパティを表示できます。この方法は、イベント オブジェクトの重要なプロパティを思い出せない人にとって非常に便利です。

6. ドラッグの原理

イベントがトリガーされると、イベント オブジェクトを通じてマウスの正確な位置を取得できます。これが抗力を実現するための鍵です。マウスが押されたとき (mousedown トリガー)、マウスの初期位置とターゲット要素の初期位置を記憶する必要があります。目標は、マウスが動くとターゲット要素も動くようにすることです。常識的に考えると、次の関係を導き出すことができます。

移動後のマウスの位置 - 初期マウスの位置 = 移動後のターゲット要素の位置 - ターゲット要素の初期位置

マウスの位置の差が dis で表される場合、ターゲット要素の位置は次のようになります。

移動後のターゲット要素の位置 = dis + ターゲット要素の初期位置

イベント オブジェクトを通じて、マウスの現在の位置を正確に知ることができるため、マウスをドラッグすると (mousemove)、マウスの移動の差を継続的に計算して、ターゲット要素の現在の位置を見つけることができます。このプロセスによりドラッグが実現されます。

マウスを離して(マウスアップして)ドラッグを終了するときは、仕上げ作業を行う必要があります。詳細についてはコードを参照してください。

7. コーディングを支援するためにマインドマッピングをお勧めします。

新しい友達から、論理的思考力が強くなくてもコードを書いたりフロントエンドの仕事をしたりできるかどうかよく聞かれます。私の答えは「はい」です。マインドマッピングの助けを借りれば、論理の欠点を簡単に補うことができるからです。また、頭の中でロジックを理解しようとするよりも明確で、エラーも起こりにくくなります。

上記の 6 番目のポイントで原則を紹介したので、実行するのはそれほど難しくありません。具体的な手順は、以下のマインド マップに明確に示されています。これらの手順に従ってコードを記述するだけです。試してみてください。簡単なはずです。

マインドマップを使用して、ドラッグプロセス全体で何をする必要があるかを明確に表現します。

8. コードの実装

パート1.準備

// ターゲット要素オブジェクトを取得します。 var oElem = document.getElementById('target');

// マウスの初期位置の x 座標と y 座標を保存するための 2 つの変数を宣言します。var startX = 0;
var 開始Y = 0;

// ターゲット要素の初期位置の x 座標と y 座標を保存するための 2 つの変数を宣言します。var sourceX = 0;
var ソースY = 0;

パート2、機能

すでにコードを投稿しているので、繰り返すつもりはありません。

// 現在のブラウザでサポートされている変換互換の書き込みメソッドを取得する関数 getTransform() {}

// 要素のプロパティを取得する function getStyle(elem, property) {}

// 要素の初期位置を取得する function getTargetPos(elem) {}

// 要素の初期位置を設定する function setTargetPos(elem, potions) {}

パート3. 3つのイベントのコールバック関数を宣言する

これら 3 つの方法は、ドラッグ アンド ドロップを実現するための核心です。上記のマインド マップの手順に厳密に従って、コードを完成させます。

//マウスダウン時のコールバックにバインドされ、eventは受信イベントオブジェクトです。function start(event) {
    // マウスの初期位置を取得します。startX = event.pageX;
    イベントページY

    // 要素の初期位置を取得します。var pos = getTargetPos(oElem);

    ソースX = pos.x;
    ソースY = pos.y;

    // バインディング document.addEventListener('mousemove', move, false);
    document.addEventListener('mouseup', end, false);
}

関数move(イベント) {
    // マウスの現在の位置を取得します。var currentX = event.pageX;
    var currentY = イベント.pageY;

    // 差を計算します var distanceX = currentX - startX;
    var 距離Y = 現在のY - 開始Y;

    // 要素の現在の位置を計算して設定する setTargetPos(oElem, {
        x: (sourceX + distanceX).toFixed(),
        y: (ソースY + 距離Y).toFixed()
    })
}

関数終了(イベント) {
    document.removeEventListener('mousemove', 移動);
    document.removeEventListener('mouseup', 終了);
    // 他のことを行う
}

はい、簡単なドラッグ アンド ドロップで問題なく実現できます。この例のデモをオンラインで表示するには、以下のリンクをクリックしてください。

ドラッグアンドドロップを実装するにはネイティブjsを使用する

9. ドラッグオブジェクトをカプセル化する

上記で実装したドラッグをドラッグ オブジェクトにカプセル化してみましょう。私たちの目標は、ドラッグ インスタンスを宣言する限り、渡されたターゲット要素が自動的にドラッグできるようになることです。

実際の開発では、オブジェクトを別の js ファイルに配置することがよくあります。この js ファイルは別のモジュールとして使用され、さまざまなモジュールの方法で整理されて使用されます。もちろん、この例では 1 つのモジュールのみが必要なので、ここでは複雑なモジュールの相互作用はありません。

変数汚染を避けるために、関数の自己実行をシミュレートするブロックレベルのスコープ内にモジュールを配置する必要があります。

(関数() {
    ...
})();

通常のモジュール構成では、多数の js ファイルを 1 つの js ファイルに単純に圧縮するため、ここでの最初のセミコロンは、前のモジュールの最後にセミコロンを使用しなかったために発生するエラーを防ぐためのものです。不可欠。もちろん、require または ES6 モジュールを使用すると、このようなことは起こりません。

オブジェクトをカプセル化するときに、プロパティとメソッドをコンストラクターまたはプロトタイプに配置できること、そして自己実行関数を追加した後で、プロパティとメソッドがモジュールの内部スコープ内に入らないようにできることがわかっています。これはクロージャに関する知識です。

私たちが直面している課題は、属性とメソッドの場所を適切に処理する方法です。

もちろん、それぞれの物体の状況は異なり、一般化することはできません。最も適切な決定を下すためには、これら 3 つの位置の特徴を明確に把握する必要があります。

  • コンストラクター内: プロパティとメソッドは現在のインスタンスのみが所有し、現在のインスタンスからのみアクセスできます。インスタンスが宣言されるたびに、メソッドが再作成されます。
  • プロトタイプでは、プロパティとメソッドはすべてのインスタンスで共有され、すべてのインスタンスからアクセスできます。新しく宣言されたインスタンスは重複するメソッドを作成しません。
  • モジュール スコープ内: 属性とメソッドはどのインスタンスからもアクセスできませんが、内部メソッドからはアクセスできます。新しく宣言されたインスタンスは、同じメソッドを繰り返し作成しません。

方法を判断するのは比較的簡単です。

新しいインスタンスが宣言されるたびにコンストラクター内のメソッドが常に繰り返し作成されるため、コンストラクター内でメソッドを宣言することは避けるようにします。

メソッドがコンストラクター内の変数を使用する必要がある場合、またはそれらをパブリックにしたい場合は、それらをプロトタイプに配置する必要があります。

メソッドをプライベートにして外部からアクセスできないようにする必要がある場合は、モジュール スコープに配置します。

属性をどこに配置するかを正しく判断することが難しい場合があり、どの属性をどの位置に配置する必要があるかを正確に定義することは困難です。これには、実際の開発での継続的な経験の要約が必要です。しかし、一般的には、最も適切な判断を下すには、これら 3 つの立場の特性を組み合わせる必要があります。

属性値がインスタンスのみによって所有される場合 (特定の人物インスタンスにのみ属することができる人物オブジェクトの名前など)、またはここでドラッグされたオブジェクト内の要素の初期位置が要素の現在の位置のみである場合、この属性はコンストラクターに配置するのが適切です。

属性が内部メソッドからのみアクセス可能な場合は、モジュール スコープに配置するのが適切です。

オブジェクト指向プログラミングに関しては、上記の点がこの記事の真髄であり、真剣に検討する価値があると思います。カプセル化する際によく考えないと、予想外のバグがたくさん発生する可能性があるので、自分の開発経験を組み合わせて、さらに考え、自分なりの意見をまとめることをお勧めします。

これらの考えに基づいて、自分でそれをカプセル化してみることができます。次に、私の考えと比較して、私たちの考えがどのように異なるかを確認します。以下の例のコメントで私の考えを述べます。

パッケージ化されたデモを見るにはクリックしてください

js ソースコード

(関数() {
    // これはプライベート プロパティであり、インスタンスによってアクセスする必要はありません var transform = getTransform();

    関数ドラッグ(セレクタ) {
        // コンストラクター内に配置されたプロパティは、各インスタンスに個別に属します。 this.elem = typeof selector == 'Object' ? selector : document.getElementById(selector);
        this.startX = 0;
        this.startY = 0;
        this.sourceX = 0;
        this.sourceY = 0;

        これを初期化します。
    }


    // プロトタイプ Drag.prototype = {
        コンストラクタ: ドラッグ、

        初期化: 関数() {
            // 最初に行う必要があること this.setDrag();
        },

        // 若干変更されていますが、getName と同様に、現在の要素の属性を取得するためにのみ使用されます。
        getStyle: 関数(プロパティ) {
            document.defaultView.getComputedStyle を返します? document.defaultView.getComputedStyle(this.elem, false)[プロパティ] : this.elem.currentStyle[プロパティ];
        },

        // 現在の要素の位置情報を取得するために使用します。前の getPosition: function() との違いに注意してください。
            var pos = {x: 0, y: 0};
            if(変換) {
                var transformValue = this.getStyle(transform);
                if(変換値 == 'なし') {
                    this.elem.style[transform] = 'translate(0, 0)';
                } それ以外 {
                    var temp = transformValue.match(/-?\d+/g);
                    位置 = {
                        x: parseInt(temp[4].trim())、
                        y: parseInt(temp[5].trim())
                    }
                }
            } それ以外 {
                if(this.getStyle('position') == 'static') {
                    this.elem.style.position = '相対';
                } それ以外 {
                    位置 = {
                        x: parseInt(this.getStyle('left') ? this.getStyle('left') : 0),
                        y: parseInt(this.getStyle('top') ? this.getStyle('top') : 0)
                    }
                }
            }

            位置を返します。
        },

        // 現在の要素の位置を設定するために使用します setPosition: function(pos) {
            if(変換) {
                this.elem.style[transform] = 'translate('+ pos.x +'px, '+ pos.y +'px)';
            } それ以外 {
                this.elem.style.left = pos.x + 'px';
                this.elem.style.top = pos.y + 'px';
            }
        },

        // このメソッドはイベントをバインドするために使用されます setDrag: function() {
            var self = this;
            this.elem.addEventListener('mousedown', 開始, false);
            関数開始(イベント) {
                イベントページを生成
                イベントページYをself.startYに代入します。

                var pos = self.getPosition();

                自己ソースX = pos.x;
                自己のソースY = pos.y;

                document.addEventListener('mousemove', 移動, false);
                document.addEventListener('mouseup', end, false);
            }

            関数move(イベント) {
                var currentX = イベント.pageX;
                var currentY = イベント.pageY;

                var 距離X = 現在のX - 自己開始X;
                var 距離Y = 現在のY - 自己開始Y;

                自己.setPosition({
                    x: (self.sourceX + distanceX).toFixed(),
                    y: (self.sourceY + distanceY).toFixed()
                })
            }

            関数終了(イベント) {
                document.removeEventListener('mousemove', 移動);
                document.removeEventListener('mouseup', 終了);
                // 他のことを行う
            }
        }
    }

    // プライベートメソッド。変換関数の互換性のある書き込みメソッドを取得するためにのみ使用されます。getTransform() {
        var 変換 = ''、
            divStyle = document.createElement('div').style,
            transformArr = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'OTransform'],

            i = 0,
            len = transformArr.length;

        for(; i < len; i++) {
            if (transformArr[i] が divStyle にある) {
                戻り値: transform = transformArr[i];
            }
        }

        変換を返します。
    }

    // 外の世界に公開する方法 window.Drag = Drag;
})();

// 使用法: 2 つのドラッグ インスタンスを宣言します。new Drag('target');
新しいドラッグ('target2');

このようなドラッグ オブジェクトはカプセル化されます。

私が提示した考え方に基づいて、より多くのコンポーネントをカプセル化してみることをお勧めします。たとえば、ポップアップ ウィンドウをカプセル化したり、ループ カルーセルをカプセル化したりします。さらに練習すれば、オブジェクト指向は問題ではなくなります。この考え方は将来いつでも使えます。

上記は、JavaScript オブジェクト指向のカプセル化とドラッグ オブジェクトの実際の応用に関する詳細な説明です。JS オブジェクト指向でカプセル化とドラッグ オブジェクトを実装する方法の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • JavaScriptのオブジェクト指向プログラミングを見てみましょう
  • ドラッグ効果を実現するための js オブジェクト指向メソッド
  • JavaScript オブジェクト指向プログラミングの詳細な説明 [クラス作成、インスタンスオブジェクト、コンストラクタ、プロトタイプなど]
  • JavaScript オブジェクト指向のコア知識と概念の要約
  • JavaScriptオブジェクト指向の7つの基本原則の詳細な例
  • JavaScriptのオブジェクト指向をご存知ですか?

<<:  Ubuntu 18.04 は mysql 5.7.23 をインストールします

>>:  Linux における nohup と & の使い方と違いの詳細な説明

推薦する

MySQL におけるさまざまな一般的な結合テーブルクエリの例の概要

この記事では、例を使用して、MySQL のさまざまな一般的な結合テーブルクエリについて説明します。ご...

MYSQL 演算子の概要

目次1. 算術演算子2. 比較演算子3. 論理演算子4. ビット演算子5. 演算子の優先順位1. 算...

hrefパラメータ転送における中国語の文字化けについて

パラメータを渡すために href が必要で、パラメータが中国語の場合、文字化けした文字が表示されます...

MySQLデータベースに中国語の文字を保存するときに発生するエラーを解決する方法を教えます

目次1. 遭遇した問題2. 問題を分析する3. 本当の問題4. 解決策5. ソリューション効果1. ...

MySQL インデックスが失敗するいくつかの状況の概要

1. インデックスはnull値を保存しないより正確に言うと、単一列インデックスには null 値は格...

Linux カーネル デバイス ドライバー仮想ファイル システムに関する注意事項

/******************** * 仮想ファイルシステム VFS **********...

Dockerを使用してプライベートGitLabを構築する2つの方法

最初の方法: docker インストール1. オープンソース版のイメージを取得する2. 対応するデー...

Dockerコンテナを更新、パッケージ化、Alibaba Cloudにアップロードする方法

今回は、実行中のコンテナをイメージにパッケージ化して Alibaba Cloud にアップロードし、...

Dockerを使用して外部からアクセス可能なMySQLを構築する詳細な説明

MySQL 8.0をインストールする docker run -p 63306:3306 -e MYS...

MySQL 5.7.15 のインストールと設定方法のグラフィック チュートリアル (Windows)

MySQL をインストールする必要があるため、インストール手順を以下のように記録します。 自分なり...

CSS3 引用のソースと出典をマークする方法

疫病のせいで家にこもりきりで、頭がおかしくなりそうなので、パソコンを起動して頭を働かせてみました。今...

mysql 8.0.16 winx64.zip インストールと設定方法のグラフィックチュートリアル

この記事では、MySQL 8.0.16 winx64.zipのインストールと設定方法の具体的なコード...

DockerはElasticsearch7.6クラスタをインストールし、パスワードを設定します

Elasticsearch 6.8 以降、無料ユーザーは X-Pack のセキュリティ機能を使用でき...

8桁の割引コードをランダムに生成し、MySQLデータベースに保存します。

現在、多くの企業が割引コードを通じてプロモーションを行っています。今では、8桁の割引コードを実装して...

CSS3 で高さと幅を不定にして垂直と水平に中央揃えするいくつかの方法

1. フレックスレイアウト 。父親 { ディスプレイ: フレックス; コンテンツの中央揃え: 中央;...