序文Iview に似た Split コンポーネントを手動でカプセル化して、領域を 2 つの領域に分割し、ドラッグして幅や高さを調整できるようにします。最終的な効果は次のようになります。 始める基本レイアウトVue プロジェクトで SplitPane コンポーネントを作成し、ページに導入して使用します。 <テンプレート> <div class="page"> <分割ペイン /> </div> </テンプレート> <スクリプト> './components/split-pane' から SplitPane をインポートします。 エクスポートデフォルト{ コンポーネント: 分割ペイン }, データ() { 戻る {} } } </スクリプト> <スタイル スコープ lang="scss"> .ページ { 高さ: 100%; パディング: 10px; 背景: #000; } </スタイル> // 分割ペイン.vue <テンプレート> <div class="split-pane"> スプリット </div> </テンプレート> <スクリプト> エクスポートデフォルト{ データ() { 戻る {} } } </スクリプト> <スタイル スコープ lang="scss"> .分割ペイン { 背景:淡い緑; 高さ: 100%; } </スタイル> SplitPane コンポーネントは、Area 1、Area 2、Sliders の 3 つの部分で構成されます。これら 3 つの要素を追加し、それぞれクラス名を追加します。.pane はエリア 1 とエリア 2 で共有されることに注意してください。 <テンプレート> <div class="split-pane"> <div class="pane ペイン-one"></div> <div class="pane-trigger"></div> <div class="pane ペイン 2"></div> </div> </テンプレート> コンテナーをフレックス レイアウトに設定し、領域 2 の flex プロパティを 1 に設定します。すると、領域 2 は領域 1 の幅に応じて適応します。 <スタイル スコープ lang="scss"> .分割ペイン { 背景:淡い緑; 高さ: 100%; ディスプレイ: フレックス; .ペイン-1 { 幅: 50%; 背景:淡い紫赤; } .ペイントリガー{ 幅: 10px; 高さ: 100%; 背景:淡いゴールデンロッド; } .ペイン2 { フレックス: 1; 背景:ターコイズ } } </スタイル> 領域 1 の幅の変更を設定することが、このコンポーネントを実装する際の核心であることがわかります。 水平レイアウトに加えて、垂直レイアウトもサポートされているため、コンポーネントに direction 属性が追加されます。この属性は外部から渡され、その値は row または column であり、親要素の flex-direction 属性にバインドされます。 <テンプレート> <div class="split-pane" :style="{ flexDirection: direction }"> <div class="pane ペイン-one"></div> <div class="pane-trigger"></div> <div class="pane ペイン 2"></div> </div> </テンプレート> <スクリプト> エクスポートデフォルト{ 小道具: { 方向: タイプ: 文字列、 デフォルト: '行' } }, データ() { 戻る {} } } </スクリプト> 水平レイアウトでは、エリア 1 は幅: 50% に設定され、スライダーは幅: 10px に設定されています。垂直レイアウトに変更すると、これら 2 つの幅が高さになります。したがって、スタイル内の 2 つの幅設定を削除し、lengthType 計算属性を追加して、インライン スタイル内の 2 つの要素の幅と高さを異なる方向に応じて設定します。 <テンプレート> <div class="split-pane" :style="{ flexDirection: direction }"> <div class="pane ペイン-one" :style="lengthType + ':50%'"></div> <div class="pane-trigger" :style="lengthType + ':10px'"></div> <div class="pane ペイン 2"></div> </div> </テンプレート> 計算: { 長さタイプ() { this.direction === 'row' ? 'width' : 'height' を返します } } 同時に、水平レイアウトでは、領域 1、領域 2、スライダーの高さはすべて 100% になり、垂直レイアウトではすべて幅: 100% に変更する必要があります。したがって、元の高さ設定を削除し、方向をコンテナーのクラスにバインドし、クラスに応じて両方のケースで 3 つの子要素の属性を 100% に設定します。 <テンプレート> <div class="split-pane" :class="direction" :style="{ flexDirection: direction }"> <div class="pane ペイン-one" :style="lengthType + ':50%'"></div> <div class="pane-trigger" :style="lengthType + ':10px'"></div> <div class="pane ペイン 2"></div> </div> </テンプレート> <スクリプト> エクスポートデフォルト{ 小道具: { 方向: タイプ: 文字列、 デフォルト: '行' } }, データ() { 戻る {} }, 計算: { 長さタイプ() { this.direction === 'row' ? 'width' : 'height' を返します } } } </スクリプト> <スタイル スコープ lang="scss"> .分割ペイン { 背景:淡い緑; 高さ: 100%; ディスプレイ: フレックス; &。行 { .ペイン{ 高さ: 100%; } .ペイントリガー{ 高さ: 100%; } } &。カラム { .ペイン{ 幅: 100%; } .ペイントリガー{ 幅: 100%; } } .ペイン-1 { 背景:淡い紫赤; } .ペイントリガー{ 背景:淡いゴールデンロッド; } .ペイン2 { フレックス: 1; 背景:ターコイズ } } </スタイル> この時点で、ページ上のコンポーネントにdirection="column"を渡すと、縦方向に変更されていることがわかります。 <テンプレート> <div class="page"> <SplitPane の方向="列" /> </div> </テンプレート> データバインディング現在のエリア1の幅(高さ)とスライダーの幅(高さ)はどちらもスタイルにハードコードされており、操作するにはjsでバインドする必要があります。まず、計算に使用できる数値をデータに入れます データ() { 戻る { panelLengthPercent: 50, // エリア 1 の幅 (%) triggerLength: 10 // スライダーの幅 (px) } } 次に、計算によって 2 つのスタイルに必要な文字列が返されます。同時に、スライダーが領域 1 と領域 2 の中央に配置されることを確認するために、領域 1 の幅をスライダーの幅の半分に縮小する必要があります。 計算: { 長さタイプ() { this.direction === 'row' ? 'width' : 'height' を返します }, パネルの長さの値() { `calc(${this.paneLengthPercent}% - ${this.triggerLength / 2 + 'px'})` を返します }, トリガー長さ値() { this.triggerLength + 'px' を返す } } 最後にテンプレートにバインドします <テンプレート> <div class="split-pane" :class="direction" :style="{ flexDirection: direction }"> <div class="pane ペイン-one" :style="長さタイプ + ':' + ペインの長さ値"></div> <div class="pane-trigger" :style="長さタイプ + ':' + トリガー長さ値"></div> <div class="pane ペイン 2"></div> </div> </テンプレート> イベントバインディングスライダーをドラッグするプロセスを想像してください。最初のステップは、スライダー上でマウスを押し、スライダーに mousedown イベントを追加することです。 <div class="pane-trigger" :style="lengthType + ':' + triggerLengthValue" @mousedown="handleMouseDown"></div> マウスを押してスライドを開始した後、mousemove イベントをリッスンする必要がありますが、マウスはページ上の任意の位置にスライドする可能性があるため、スライダーではなくドキュメント全体をリッスンする必要があることに注意してください。ユーザーがマウスを離すと、ドキュメント全体のマウス移動リスナーがキャンセルされるので、マウスが押された瞬間に、マウス移動とマウス解放の2つのイベントがドキュメントに追加される必要があります。 メソッド: { // スライダーを押す handleMouseDown(e) { document.addEventListener('mousemove', this.handleMouseMove) document.addEventListener('mouseup', this.handleMouseUp) }, // スライダーを押した後にマウスを移動する handleMouseMove(e) { console.log('ドラッグ') }, // スライダーを解放する handleMouseUp() { document.removeEventListener('mousemove', this.handleMouseMove) } } 実際に制御したいのはエリア 1 の幅で、エリア 1 の幅は現在のマウスとコンテナーの左側の間の距離と等しくなります。つまり、マウスが下の図の円の位置に移動すると、エリア 1 の幅は中央の長さと等しくなります。 この長さは、現在のマウスとページの左端の間の距離から、コンテナーとページの左端の間の距離を引いた値に基づいて計算できます。つまり、緑の長さは赤から青を引いた値に等しくなります。 コンテナのDOM情報を取得するには、コンテナにrefを追加します。 ... <div ref="splitPane" class="split-pane" :class="direction" :style="{ flexDirection: direction }"> ... ref の getBoundingClientRect() を印刷すると、次の情報が表示されます。 console.log(this.$refs.splitPane.getBoundingClientRect()) ここで、left はページの左側からのコンテナーの距離を表し、width はコンテナーの幅を表します。 // スライダーを押した後にマウスを移動する handleMouseMove(e) { const clientRect = this.$refs.splitPane.getBoundingClientRect() 定数オフセット = e.pageX - clientRect.left 定数paneLengthPercent = (オフセット / clientRect.width) * 100 this.paneLengthPercent = ペインの長さパーセント }, 縦向きレイアウトに対応しています。 // スライダーを押した後にマウスを移動する handleMouseMove(e) { const clientRect = this.$refs.splitPane.getBoundingClientRect() パネルの長さパーセントを 0 にします if (this.direction === 'row') { 定数オフセット = e.pageX - clientRect.left ペインの長さパーセント = (オフセット / クライアント矩形の幅) * 100 } それ以外 { 定数オフセット = e.pageY - clientRect.top ペインの長さパーセント = (オフセット / クライアント矩形の高さ) * 100 } this.paneLengthPercent = ペインの長さパーセント }, 最適化この時点では要件は満たされているように見えますが、一般的なコンポーネントとしては、まだ最適化が必要な領域がいくつかあります。 ジッター問題を最適化するスライダーの幅を大きい値に設定すると、次のようにジッターの問題が見つかります。 現在の計算ロジックでは、スライダーの幅を考慮せずに、マウスがスライダーの中央にあると常に想定されるため、スライダーのいずれかの側を押して少し動かすと、大きなシフトが発生します。 dotaのスライダーの左(上)側からの現在のマウスオフセットを定義します データ() { 戻る { panelLengthPercent: 50, // エリア 1 の幅 (%) triggerLength: 100, // スライダーの幅 (px) triggerLeftOffset: 0 // スライダーの左(上)側からのマウスのオフセット} } この値は、マウスからページの左側までの距離から、スライダーからページの左側までの距離を引いた値に等しくなります (e.srcElement.getBoundingClientRect() 経由)。スライダーが押されるたびに割り当てられ、水平/垂直レイアウトを区別します: 赤 - 青 = 緑 // スライダーを押す handleMouseDown(e) { document.addEventListener('mousemove', this.handleMouseMove) document.addEventListener('mouseup', this.handleMouseUp) if (this.direction === 'row') { this.triggerLeftOffset = e.pageX - e.srcElement.getBoundingClientRect().left } それ以外 { this.triggerLeftOffset = e.pageY - e.srcElement.getBoundingClientRect().top } }, この triggerLeftOffset を使用すると、領域 1 の幅の設定は、マウスからコンテナーの左側までの距離から、マウスからスライダーの左側までの距離 (triggerLeftOffset) を引いた値に、スライダーの幅の半分を加えた値になります。 // スライダーを押した後にマウスを移動する handleMouseMove(e) { const clientRect = this.$refs.splitPane.getBoundingClientRect() パネルの長さパーセントを 0 にします if (this.direction === 'row') { 定数オフセット = e.pageX - clientRect.left - this.triggerLeftOffset + this.triggerLength / 2 ペインの長さパーセント = (オフセット / クライアント矩形の幅) * 100 } それ以外 { 定数オフセット = e.pageY - clientRect.top - this.triggerLeftOffset + this.triggerLength / 2 ペインの長さパーセント = (オフセット / クライアント矩形の高さ) * 100 } this.paneLengthPercent = ペインの長さパーセント }, ジッターの問題はもうありません 2番目のマウススタイルを最適化するマウスがスライダー上を通過すると、ドラッグできることをユーザーに知らせるためにスタイルが変更されます。水平レイアウトと垂直レイアウトのスライダー CSS にそれぞれマウス スタイルの変更を追加します。 <スタイル スコープ lang="scss"> .分割ペイン { 背景:淡い緑; 高さ: 100%; ディスプレイ: フレックス; &。行 { .ペイン{ 高さ: 100%; } .ペイントリガー{ 高さ: 100%; cursor: col-resize; // ここ} } &。カラム { .ペイン{ 幅: 100%; } .ペイントリガー{ 幅: 100%; cursor: row-resize; // ここ} } .ペイン-1 { 背景:淡い紫赤; } .ペイントリガー{ 背景:淡いゴールデンロッド; } .ペイン2 { フレックス: 1; 背景:ターコイズ } } </スタイル> 3スライドの制限を最適化するユニバーサル コンポーネントとして、最小および最大のスライド距離制限を設定するための外部関数を提供し、min と max の 2 つのプロパティを受け取る必要があります。 小道具: { 方向: タイプ: 文字列、 デフォルト: '行' }, 最小: { タイプ: 数値、 デフォルト: 10 }, 最大: { タイプ: 数値、 デフォルト: 90 } }, handleMouseMoveに判定を追加します: // スライダーを押した後にマウスを移動する handleMouseMove(e) { const clientRect = this.$refs.splitPane.getBoundingClientRect() パネルの長さパーセントを 0 にします if (this.direction === 'row') { 定数オフセット = e.pageX - clientRect.left - this.triggerLeftOffset + this.triggerLength / 2 ペインの長さパーセント = (オフセット / クライアント矩形の幅) * 100 } それ以外 { 定数オフセット = e.pageY - clientRect.top - this.triggerLeftOffset + this.triggerLength / 2 ペインの長さパーセント = (オフセット / クライアント矩形の高さ) * 100 } ペインの長さパーセントが this.min 未満の場合 パネルの長さパーセント = this.min } ペインの長さパーセントが this.max の場合 パネルの長さパーセント = this.max } this.paneLengthPercent = ペインの長さパーセント } 4つのパネルのデフォルトの幅とスライダーの幅を最適化します一般的なコンポーネントとして、パネルの初期化比率とスライダーの幅も外部ユーザーが決定する必要があります。 小道具: { 方向: タイプ: 文字列、 デフォルト: '行' }, 最小: { タイプ: 数値、 デフォルト: 10 }, 最大: { タイプ: 数値、 デフォルト: 90 }, パネルの長さパーセント: { タイプ: 数値、 デフォルト: 50 }, トリガーの長さ: { タイプ: 数値、 デフォルト: 10 } }, データ() { 戻る { triggerLeftOffset: 0 // スライダーの左(上)側からのマウスのオフセット} }, このページでは、paneLengthPercent を渡す必要があります。paneLengthPercent はデータで定義されたデータである必要があり、この値は動的に変更する必要があるため、.sync 修飾子でマークされている必要があることに注意してください。 // ページ.vue <テンプレート> <div class="page"> <SplitPane direction="row" :paneLengthPercent.sync="paneLengthPercent" /> </div> </テンプレート> ... データ() { 戻る { パネルの長さパーセント: 30 } } ... 次に、this.$emit を通じてイベントをトリガーして、コンポーネントの handleMouseMove の panelLengthPercent 値を変更します。 // スライダーを押した後にマウスを移動する handleMouseMove(e) { const clientRect = this.$refs.splitPane.getBoundingClientRect() パネルの長さパーセントを 0 にします if (this.direction === 'row') { 定数オフセット = e.pageX - clientRect.left - this.triggerLeftOffset + this.triggerLength / 2 ペインの長さパーセント = (オフセット / クライアント矩形の幅) * 100 } それ以外 { 定数オフセット = e.pageY - clientRect.top - this.triggerLeftOffset + this.triggerLength / 2 ペインの長さパーセント = (オフセット / クライアント矩形の高さ) * 100 } ペインの長さパーセントが this.min 未満の場合 パネルの長さパーセント = this.min } ペインの長さパーセントが this.max の場合 パネルの長さパーセント = this.max } this.$emit('update:paneLengthPercent', panelLengthPercent) // ここ}, この時点で、コンポーネントの要素情報は外部のプロパティによって制御できます。 5つのスロットを最適化コンテナコンポーネントなので、コンテンツを追加できないと意味がありません。2 つの領域にそれぞれ 2 つの名前付きスロットを追加します。 <テンプレート> <div ref="splitPane" class="split-pane" :class="direction" :style="{ flexDirection: direction }"> <div class="pane ペイン-one" :style="長さタイプ + ':' + ペイン長さ値"> <スロット名="1"></スロット> </div> <div クラス="ペイントリガー" :style="長さタイプ + ':' + トリガー長さ値" @mousedown="ハンドルマウスダウン"> </div> <div class="pane ペイン 2"> <スロット名="2"></スロット> </div> </div> </テンプレート> 6つの禁止選択を最適化するドラッグ処理中に、領域内にテキスト コンテンツがある場合、テキストが選択される可能性があり、スライダーに選択禁止効果が追加されます。 ... .ペイントリガー{ ユーザー選択: なし; 背景:淡いゴールデンロッド; } ... 仕上げるコンポーネントの完全なコード背景色は記事の表示目的のみに保持され、実際の使用時には削除されます。 <テンプレート> <div ref="splitPane" class="split-pane" :class="direction" :style="{ flexDirection: direction }"> <div class="pane ペイン-one" :style="長さタイプ + ':' + ペイン長さ値"> <スロット名="1"></スロット> </div> <div クラス="ペイントリガー" :style="長さタイプ + ':' + トリガー長さ値" @mousedown="ハンドルマウスダウン" </div> <div class="pane ペイン 2"> <スロット名="2"></スロット> </div> </div> </テンプレート> <スクリプト> エクスポートデフォルト{ 小道具: { 方向: タイプ: 文字列、 デフォルト: '行' }, 最小: { タイプ: 数値、 デフォルト: 10 }, 最大: { タイプ: 数値、 デフォルト: 90 }, パネルの長さパーセント: { タイプ: 数値、 デフォルト: 50 }, トリガーの長さ: { タイプ: 数値、 デフォルト: 10 } }, データ() { 戻る { triggerLeftOffset: 0 // スライダーの左(上)側からのマウスのオフセット} }, 計算: { 長さタイプ() { this.direction === 'row' ? 'width' : 'height' を返します }, パネルの長さの値() { `calc(${this.paneLengthPercent}% - ${this.triggerLength / 2 + 'px'})` を返します }, トリガー長さ値() { this.triggerLength + 'px' を返す } }, メソッド: { // スライダーを押す handleMouseDown(e) { document.addEventListener('mousemove', this.handleMouseMove) document.addEventListener('mouseup', this.handleMouseUp) if (this.direction === 'row') { this.triggerLeftOffset = e.pageX - e.srcElement.getBoundingClientRect().left } それ以外 { this.triggerLeftOffset = e.pageY - e.srcElement.getBoundingClientRect().top } }, // スライダーを押した後にマウスを移動する handleMouseMove(e) { const clientRect = this.$refs.splitPane.getBoundingClientRect() パネルの長さパーセントを 0 にします if (this.direction === 'row') { 定数オフセット = e.pageX - clientRect.left - this.triggerLeftOffset + this.triggerLength / 2 ペインの長さパーセント = (オフセット / クライアント矩形の幅) * 100 } それ以外 { 定数オフセット = e.pageY - clientRect.top - this.triggerLeftOffset + this.triggerLength / 2 ペインの長さパーセント = (オフセット / クライアント矩形の高さ) * 100 } ペインの長さパーセントが this.min 未満の場合 パネルの長さパーセント = this.min } ペインの長さパーセントが this.max の場合 パネルの長さパーセント = this.max } this.$emit('update:paneLengthPercent', ペインの長さパーセント) }, // スライダーを解放する handleMouseUp() { document.removeEventListener('mousemove', this.handleMouseMove) } } } </スクリプト> <スタイル スコープ lang="scss"> .分割ペイン { 背景:淡い緑; 高さ: 100%; ディスプレイ: フレックス; &。行 { .ペイン{ 高さ: 100%; } .ペイントリガー{ 高さ: 100%; カーソル: col-resize; } } &。カラム { .ペイン{ 幅: 100%; } .ペイントリガー{ 幅: 100%; カーソル: 行のサイズ変更; } } .ペイン-1 { 背景:淡い紫赤; } .ペイントリガー{ ユーザー選択: なし; 背景:淡いゴールデンロッド; } .ペイン2 { フレックス: 1; 背景:ターコイズ } } </スタイル> コンポーネントの使用例背景色は記事の表示目的のみに保持され、実際の使用時には削除されます。 <テンプレート> <div class="page"> <分割ペイン 方向="列" :min="20" :max="80" :トリガーの長さ="20" :paneLengthPercent.sync="ペインの長さパーセント" > <テンプレート v-slot:one> <div> エリア1</div> </テンプレート> <テンプレート v-slot:two> <div> エリア2 </テンプレート> </分割ペイン> </div> </テンプレート> <スクリプト> './components/split-pane' から SplitPane をインポートします。 エクスポートデフォルト{ コンポーネント: 分割ペイン }, データ() { 戻る { パネルの長さパーセント: 30 } } } </スクリプト> <スタイル スコープ lang="scss"> .ページ { 高さ: 100%; パディング: 10px; 背景: #000; } </スタイル> これで、Vue が Split を使用してユニバーサルなドラッグ アンド スライド分割パネル コンポーネントをカプセル化する方法についての説明は終わりです。Vue のドラッグ アンド スライド分割パネルに関する関連コンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、次の関連記事を引き続き参照してください。今後も 123WORDPRESS.COM を応援していただければ幸いです。 以下もご興味があるかもしれません:
|
<<: nginx で第 3 レベルドメイン名を設定する方法の例
>>: MySQL 5.7 mysql コマンドラインクライアントの使用コマンドの詳細
この記事では、MySQL 8.0.12解凍版のインストールチュートリアルを参考までに紹介します。具体...
デフォルトでは、コンテナ内のプロセスは root ユーザー権限で実行され、この root ユーザーは...
目次1. dfコマンド2. duコマンド3. fsckファイルシステム修復コマンド4. ディスクステ...
CSS 表示プロパティ注: !DOCTYPE が指定されている場合、Internet Explore...
IPツールを取得 lombok.extern.slf4j.Slf4j をインポートします。 org....
サーバーも 2 つあります。準備:コンテナのホスト名を設定する consul: kv タイプのストレ...
導入保存時と読み取り時に CHAR 型と VARCHAR 型の違いを本当にご存知ですか?まずいくつか...
目次物体オブジェクト定義オブジェクトのメンバーを反復処理するJS組み込みオブジェクト数学オブジェクト...
導入Alibaba Cloud のような OSS ストレージ サービスを使用している場合は、サービス...
実験環境• 最小限のインストール済みの CentOS 7.3 仮想マシン• 構成: 1 コア/512...
1. 子コンポーネントのthis.$parent.eventを通じて親コンポーネントメソッドを直接呼...
目次概要画像圧縮とはJPEG/JPG JPGの利点JPGの使用シナリオJPGの欠点MozJPEG を...
この記事では、アバター変更機能を実装するためのJavaScriptの具体的なコードを参考までに共有し...
参照: https://www.jb51.net/article/112612.htmシステム内のJ...
目次1. 問題を発見する2.重複したデータを残さずにすべて削除する3. 削除テーブルから重複データを...