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 ルートユーザーアカウントのパスワードをリセットする問題を解決する

推薦する

CentOS の Nginx 公式 Yum ソースの設定を詳しく解説

私はプロジェクトの展開にAlibaba Cloudから購入したCentOSを使用しています。最近、プ...

タグ li はブロックレベル要素ですか?

なぜ高さを設定できるのでしょうか。<h1 /> などの要素とは異なり、「セミインライン」...

CSS flex 複数列レイアウト

基本的な3列レイアウト 。容器{ ディスプレイ: フレックス; 幅: 500ピクセル; 高さ: 20...

Mysql テーブル、列、データベースの追加、削除、変更、クエリの問題の概要

以下は私がまとめた基本的なSQL知識です。主に参考資料として、また将来の他の初心者の助けとして、私自...

Vue プロジェクトは左スワイプ削除機能を実装します (完全なコード)

成果を達成するコードは次のとおりですhtml <テンプレート> <div> ...

MySQL 8.0 DDLアトミック機能と実装原則

1. DDLアトミック性の概要8.0 より前は、統一されたデータ ディクショナリ dd はありません...

MySQL パーティションテーブルのベストプラクティスガイド

序文:パーティショニングはテーブル設計パターンです。一般的に、テーブル パーティショニングとは、条件...

マージントップ崩壊現象とその具体的解決策

マージントップの崩壊とはmargin-top の崩壊は、CSS ボックス モデルで発生する現象です。...

Linux で履歴コマンドを表示および実行する方法

履歴コマンドを表示し、指定されたコマンドを実行します owen@owen:~/owen/softwa...

Linux で固定 IP を設定する方法 (テスト済みで効果的)

まず、仮想マシンを開きます xshell5 を開いて仮想マシンに接続します (より便利です。Linu...

JavaScript の基礎におけるデータ型の詳細な説明

目次1. データ型1.1 なぜデータ型が必要なのか? 1.2 変数のデータ型1.3 データ型の分類2...

CSS3 でシンプルな白い雲が浮かぶ背景効果を実現

これは非常にシンプルな純粋な CSS3 の白い雲の浮遊する背景効果です。浮かぶ白い雲の特殊効果は、C...

MySQL 外部キー設定方法の例

1. 外部キーの設定方法1. MySQL では、2 つのテーブルを関連付けるために、外部キー (FO...

フィルターを使用して画像に透明な CSS を書く方法

フィルターを使用して画像に透明な CSS を書く方法コードをコピーコードは次のとおりです。 html...

Docker Hubの動作原理と実装プロセスの分析

GitHub が提供するコード ホスティング サービスと同様に、Docker Hub はイメージ ホ...