Vueカスタム指示により、ポップアップウィンドウのドラッグ4辺ストレッチと対角ストレッチ効果を実現

Vueカスタム指示により、ポップアップウィンドウのドラッグ4辺ストレッチと対角ストレッチ効果を実現

導入

同社の最近の Vue フロントエンド プロジェクトの要件: ポップアップ ウィンドウのドラッグ、4 辺の伸縮、対角線の伸縮、およびポップアップ ウィンドウの境界処理を実現すること。私は、みんなで共有して一緒に学習できるように、vue のカスタム指示を使用して drag.js ファイルを作成しました。次のコードは、参考のために抽出した概略的なデモです。これはフロントエンド初心者としての私の最初の技術共有です。間違いがあれば、批判して訂正してください。

ページレイアウト

<テンプレート>
  <div
    クラス="パラメータ"
    v-ダイアログドラッグ
  >
    <div class="title">タイトル<div class="close">
        <画像
          src="../assets/close.png"
          代替案=""
        >
      </div>
    </div>
    <div class="content">コンテンツエリア</div>
  </div>
</テンプレート>
<スタイル lang="less">
.パラメータ{
  高さ: 569px;
  幅: 960ピクセル;
  位置: 絶対;
  左: 50%;
  上位: 50%;
  左マージン: calc(-960px / 2);
  上マージン: calc(-569px / 2);
  zインデックス: 999;
  背景: #fff;
  ボックスのサイズ: 境界線ボックス;
  ボックスの影: 0px 12px 32px 0px rgba(0, 0, 0, 0.08);
  境界線の半径: 2px;
  。タイトル {
    ディスプレイ: フレックス;
    フォントサイズ: 16px;
    高さ: 48px;
    行の高さ: 48px;
    背景: #f5f5f5;
    ボックスのサイズ: 境界線ボックス;
    ボックスシャドウ: インセット 0px -1px 0px rgba(0, 0, 0, 0.12);
    境界線の半径: 2px 2px 0px 0px;
    パディング: 0 20px;
    zインデックス: 99;
    フォントサイズ: 16px;
    フォントの太さ: 500;
    色: rgba(0, 0, 0, 0.85);
    。近い {
      画像 {
        幅: 10px;
      }
      margin-left: auto; // 右揃え}
  }
  。コンテンツ {
    ディスプレイ: フレックス;
    コンテンツの中央揃え: 中央;
    アイテムの位置を中央揃えにします。
    高さ: calc(100% - 48px);
    ボックスのサイズ: 境界線ボックス;
    背景: #fff;
    オーバーフロー:自動;
  }
}
</スタイル>

ページレイアウトの実際の効果は次のとおりです。

ここに画像の説明を挿入

drag.js ファイル

drag.js ファイルを main.js にグローバルにインポートすることも、ポップアップ コンポーネントに個別にインポートして、他の使用方法があるかどうかを確認することもできます。

プロジェクトディレクトリのスクリーンショット

ここに画像の説明を挿入

main.js は drag.js をグローバルにインポートします

'vue' から Vue をインポートします
'element-ui' から ElementUI をインポートします。
'element-ui/lib/theme-chalk/index.css' をインポートします。
'./App.vue' からアプリをインポートします。
'../drag.js' をインポートします

Vue.config.productionTip = false
Vue.js の ElementUI 要素をオーバーライドします。

新しいVue({
  レンダリング: h => h(App),
}).$mount('#app')

ポップアップウィンドウのドラッグ実装と境界制限

'vue' から Vue をインポートします
// v-dialogDrag: ポップアップウィンドウのドラッグ + 水平方向の伸縮 + 対角方向の伸縮 Vue.directive('dialogDrag', {
  バインド(el) {
  	// dialogHeaderEl はタイトルバーです。ドラッグの mousedown イベントをバインドします。const dialogHeaderEl = el.querySelector('.title')
   	// dragDom は命令にバインドされた dom 要素です。区別を容易にするために変数を定義します。const dragDom = el
    // すべての CSS 属性を取得します。互換性のある書き込み方法、つまり dom element.currentStyle firefox google window.getComputedStyle(dom element, null);
    const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null) 
    // マウス押下イベントを定義する const moveDown = e => {
      // e.clientX, Y: ブラウザの表示ウィンドウに対するマウスの X、Y 座標 // offsetTop、offsetLeft: 現在の要素の offsetParent 要素の上端と左端に対する距離。ここでは、title には位置オフセットがないため、0 です。	
      : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

      // IEとの互換性のため
      スタイルL === 'auto'の場合、スタイルL = '0px'
      styT = sty.top とします。

      // IEでは、最初に取得される値はコンポーネント自身の50%であり、その値は移動後にpxに割り当てられることに注意してください。
      (sty.left.includes('%')の場合){
        styL = +document.body.clientWidth * (+styL.replace(/%/g, '') / 100)
        styT = +document.body.clientHeight * (+styT.replace(/%/g, '') / 100)
      } それ以外 {
        styL = +styL.replace(/\px/g, '')
        styT = +styT.replace(/\px/g, '')
      }   

      document.onmousemove = 関数 (e) {
        // イベント委譲を通じて移動距離を計算する let left = e.clientX - disX
        top = e.clientY - disY とします。

        // 境界処理 if (-(left) > minDragDomLeft) {
          左 = -(minDragDomLeft)
        } そうでない場合 (左 > maxDragDomLeft) {
          左 = maxDragDomLeft
        }

        if (-(top) > minDragDomTop) {
          上 = -(minDragDomTop)
        } そうでない場合 (top > maxDragDomTop) {
          上 = maxDragDomTop
        }

        // 現在の要素を移動する dragDom.style.left = `${left + styL}px`
        dragDom.style.top = `${top + styT}px`
        
	// マウスを離したときにポップアップウィンドウが動かないようにする document.onmouseup = function () {
        ドキュメント.onmousemove = null
        document.onmouseup = null
      }
    }
    dialogHeaderEl.onmousedown = 下へ移動    
  }
})

マウスポインターのホバースタイル

ポップアップウィンドウはブラウザのドラッグの実際の効果を参照するため、カーソル:移動ホバースタイルを設定しません。移動を設定する場合は、境界判定条件を追加する必要があります。

マウスホバーポインターのタイプを決定します。 x > left + width - 5 。ここで、 5 は設定した伸縮可能な領域です。ポップアップウィンドウでは境界線とパディングを設定できないため、実際にドラッグ可能な要素はありません。そのため、手動で 5px を設定します (必要に応じて変更できます)。

マウスポインターホバーのその他のスタイルについては、MDNを参照してください。

 // マウスホバースタイルを定義する const CURSORTYPE = {
      上: 'n-resize'、
      下: 's-resize'、
      左: 'w-resize'、
      右:「e-resize」、
      // right_top は、次のコードでデータ処理を容易にするために記述されています right_top: 'ne-resize', 
      left_top: 'nw-resize'、
      left_bottom: 'sw-resize',
      right_bottom: 'se-resize'、
      デフォルト: 'デフォルト',
    };

    // マウスホバーポインターのタイプを決定する const checkType = obj => {
      定数 { x, y, 左, 上, 幅, 高さ } = obj
      タイプする
      (x > 左 + 幅 - 5 && el.scrollTop + y <= 上 + 高さ - 5 && 上 + 5 <= y) の場合 {
        タイプ = '右'
      }
      そうでない場合 (left + 5 > x && el.scrollTop + y <= top + height - 5 && top + 5 <= y) {
        タイプ = '左'
      } そうでない場合 (el.scrollTop + y > top + height - 5 && x <= left + width - 5 && left + 5 <= x) {
        タイプ = '下'
      } そうでない場合 (上 + 5 > y && x <= 左 + 幅 - 5 && 左 + 5 <= x) {
        タイプ = 'トップ'
      } そうでない場合 (x > 左 + 幅 - 5 && el.scrollTop + y > 上 + 高さ - 5) {
        タイプ = '右下'
      } そうでない場合 (left + 5 > x && el.scrollTop + y > top + height - 5) {
        タイプ = '左下'
      } そうでない場合 (上 + 5 > y && x > 左 + 幅 - 5) {
        タイプ = 'right_top'
      } そうでない場合 (上 + 5 > y && 左 + 5 > x) {
        タイプ = 'left_top'
      }
      戻り値の型 || 'default'
    }

四辺ストレッチと斜めストレッチ

対角線引き伸ばしの過程で、私の考えには少しずれがありました。ブラウザウィンドウは、X軸方向、Y軸方向、ベベルエッジの3つの方向に対角線引き伸ばしができることを発見したので、3つの状況に分けて判断しました。しかし、実際のポップアップウィンドウ効果は少ししか引き伸ばせず、引き伸ばしの要件を満たしていません。考えてみると、実際の対角伸縮は、X軸とY軸と基準ベクトルの重ね合わせであることがわかりました。

対角ストレッチは X 軸と Y 軸の重ね合わせであるため、4 辺ストレッチ関数をカプセル化し、対角ストレッチの対応する X 軸と Y 軸を直接呼び出してコード量を削減することを検討します。データを渡す場合、対角ストレッチでは 2 つの値を渡す必要があるのに対し、四辺ストレッチでは 1 つの値のみを渡す必要があるため、データをパッケージ化する必要があります。たとえば、右側はデータ['right', null]を渡し、右下隅はデータ['right', 'bottom']を渡します。

  // 境界条件を決定する const boundaryLimit = obj => {
      const { 左、上、幅、高さ、diffX、diffY、画面高さ、画面幅、arr } = obj
      (arr[0] == '右' || arr[1] == '右') の場合 {
        if (width + diffX > screenWidth - left) {
          dragDom.style.width = 画面幅 - 左 + 'px'
        } それ以外 {
          dragDom.style.width = 幅 + diffX + 'px'
        }
      }
      arr[0] == '左' || arr[1] == '左' の場合 {
        (幅 - diffX > 幅 + 左)の場合{
          dragDom.style.width = 幅 + 左 + 'px'
          dragDom.style.left = - parseInt(sty.marginLeft) + 'px'
        } それ以外 {
          dragDom.style.width = 幅 - diffX + 'px'
          // 実際には left = left + marginLeft です。計算するときは marginLeft を減算する必要があります。dragDom.style.left = left + diffX - parseInt(sty.marginLeft) + 'px'
        }
      }
      (arr[0] == 'トップ' || arr[1] == 'トップ') {
        if (高さ - diffY > 高さ + 上) {
          dragDom.style.height = 高さ + 上 + 'px'
          dragDom.style.top = - parseInt(sty.marginTop) + 'px'
        } それ以外 {
          dragDom.style.height = 高さ - diffY + 'px'
          // top は実際には top + marginTop です。計算時に MarginTop を減算する必要があります。dragDom.style.top = top + diffY - parseInt(sty.marginTop) + 'px'
        }
      }
      もし (arr[0] == '下' || arr[1] == '下') {
        if (height + diffY > screenHeight - top) {
          dragDom.style.height = スクリーン高さ - 上
        } それ以外 {
          dragDom.style.height = 高さ + diffY + 'px'
        }
      }
    }
    ドラッグDom.onmousedown = e => {
      定数 x = e.clientX
      定数 y = e.clientY
      定数幅 = dragDom.clientWidth
      定数高さ = dragDom.clientHeight
      定数 left = dragDom.offsetLeft
      定数 top = dragDom.offsetTop
      const screenWidth = document.documentElement.clientWidth || document.body.clientWidth
      const screenHeight = document.documentElement.clientHeight || document.body.clientHeight
      // dragDom.style.userSelect = 'なし'
      type = checkType({x, y, left, top, width, height}) とします。
      // ポップアップウィンドウのヘッダーかどうかを判定します if (x > left &&
        x < 左 + 幅 &&
        y > トップ + 5 &&
        y < 上 + dialogHeaderEl.clientHeight) {
        // dialogHeaderEl.onmousedown = moveDown
      } それ以外 {
        document.onmousemove = 関数 (e) {
          // 移動時にデフォルトのイベントを無効にする e.preventDefault()
          endX = e.clientX とします。
          endY = e.clientY とします。
          diffX = endX - x とします。
          diffY = endY - y とします。
          アーー
          // コード判断を簡素化するために型を配列形式に変換し、if (type.indexOf('_') == -1) を呼び出します。
            arr = [タイプ, '']
          } それ以外 {
            arr = type.split('_')
          }
          boundaryLimit({ 左、上、幅、高さ、diffX、diffY、画面高さ、画面幅、arr })
        }
        // ストレッチ終了 document.onmouseup = function () {
          ドキュメント.onmousemove = null

          document.onmouseup = null
        }
      }
    }

ストレッチ干渉

ポップアップ ウィンドウはoverflow: auto設定されているため、ストレッチ処理によって右側と下部にスクロール バーが必然的に生成されます。実際のストレッチ中は、スクロール バーがストレッチ領域を妨害します。解決策は、ポップアップ ウィンドウの右側と下部に空の div バーを追加し、実際のストレッチ領域を空の div にすることです。 (空の div バーの幅と高さは 5px で、これは以前に設定したストレッチ領域と一致しています)

ここに画像の説明を挿入

<テンプレート>
  <div
    クラス="パラメータ"
    v-ダイアログドラッグ
  >
    <div class="title">タイトル<div class="close">
        <画像
          src="../assets/close.png"
          代替案=""
        >
      </div>
    </div>
    <div class="content">コンテンツエリア</div>
    <div class="rightBlank">123</div>
    <div class="bottomBlank">456</div>
  </div>
</テンプレート>

変更後のページ効果は

ここに画像の説明を挿入

添付プロジェクト倉庫住所

ポップアップウィンドウのドラッグ、4辺のストレッチ、対角線のストレッチを実装するためのVueカスタム命令に関するこの記事はこれで終わりです。関連するvueカスタム命令のポップアップウィンドウのドラッグコンテンツの詳細については、123WORDPRESS.COMの以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも123WORDPRESS.COMを応援してください。

以下もご興味があるかもしれません:
  • VUEは、マウスをドラッグアンドドロップしてウィンドウサイズを変更するためのStudio管理バックグラウンドを実装しています。
  • VUEは、自由にドラッグできるポップアップコンポーネントを実装しています。
  • Vue の一時停止されたドラッグ可能なフローティング ボタンのサンプル コード
  • Vueは視覚的なドラッグページエディタを実装します
  • Vue ベースのドラッグ アンド ドロップ機能を実装する
  • Vueをベースにドラッグ効果を実現
  • Vueはdivドラッグアンドドロップを実装します
  • Vueはドラッグアンドドロップを実装します
  • Vue draggableは左から右へのドラッグ機能を実現します
  • Vue はドラッグウィンドウ機能を実装します

<<:  Linux tac コマンドの実装例

>>:  Mysql ルートユーザーアカウントのパスワードをリセットする問題を解決する

推薦する

MySQL 文字セットの変更に関する実践的なチュートリアル

序文: MySQL では、システムが多くの文字セットをサポートしており、異なる文字セット間にはわずか...

サーバーストレステストの概念と方法 (TPS/同時実行性)

目次1 ストレステストの指標1.1 秒あたり1.2 クォータ1.3 平均処理時間(RT) 1.4 同...

JavaScriptスコープについての簡単な説明

目次1. 範囲1. グローバルな範囲2. ローカルスコープ2. 変数のスコープ1. グローバル変数2...

Reactでプロキシを有効にする2つの実用的な方法

プロキシを有効にする2つの方法React には、直接使用できるカプセル化された Ajax リクエスト...

MySQL の重要なパフォーマンス インデックスの計算と最適化方法の概要

1 QPS 計算 (1 秒あたりのクエリ数) MyISAMエンジンベースのDBの場合 MySQL&g...

MySQLの挿入文字化け問題を解決する方法

問題の説明: MySQL に中国語の文字を挿入する場合、または MySQL では中国語の文字が正常に...

ReactはExcelファイルのインポートとエクスポートを実装します

目次プレゼンテーション層ビジネスレイヤーコアプラグイン xlsx ExcelインポートExcelエク...

ReactとReduxの関係を詳しく説明

目次1. reduxとreactの関係2. Reactのマルチコンポーネント共有3. reduxの3...

Ubuntu Linuxシステムをインストールするときにハードディスクをパーティション分割する最も合理的な方法の詳細な説明

Windows または Linux オペレーティング システムをインストールするかどうかに関係なく、...

MySQL 8.0.12 のインストールと設定のグラフィックチュートリアル

MySQL 8.0.12 のダウンロードとインストールのチュートリアルを録画し、全員と共有しました。...

Promise カプセル化 wx.request メソッド

前回の記事では、Promise を使用して小さなプログラム wx.request をカプセル化する実...

WeChatアプレットでのwxsファイルの素晴らしい使い方をいくつか紹介します

目次序文応用フィルタードラッグファイル間での参照の受け渡しwxsはjsロジック層にパラメータを渡しま...

Vue3 での provide と injection の使用

1. provideとinjectの説明Provide と Inject により、ネストされたコンポ...

同じ日の最初の3つのデータを取得するためのMySQLタイムラインデータ

テーブルデータを作成する テーブル `praise_info` を作成します ( `id` bigi...

テーブルタグ(テーブル)詳細

<br />テーブルは、昔から誰もが使ってきたタグで、今も使われています。しかし、現在の...