Vueは視覚的なドラッグページエディタを実装します

Vueは視覚的なドラッグページエディタを実装します

オンラインアドレス(VPNを使用するとより高速になります)

ビジュアルページエディターなんて、手の届かないものですよね?まずはアニメーション画像を見てみましょう!

この機能を実装する前に、インターネットで多くの情報を参照しましたが、結局何も見つかりませんでした。さまざまな記事はすべて、過去の自分のことを語っていました。

それで、この時点で、それをどのように達成するかを自分で考え出す必要がありますか?

考慮すべき事項:

  • ドラッグアンドドロップの実装
  • データ構造の定義
  • コンポーネントの分割
  • 保守性と拡張性

オブジェクト参照: これは私が今まで見た中で最もクールなトリックです。詳細を一つずつ説明しましょう。 !

ドラッグアンドドロップの実装

ドラッグイベント

ここでは H5 のドラッグ イベントが主に次の目的で使用されます。

dragstart // 要素のドラッグを開始したときにトリガーされます draggable // ドラッグ可能な要素を指定します dragend // ドラッグ操作が終了したときにトリガーされます dragover // ドラッグされた要素がドロップ可能なターゲット上に移動したときにトリガーされます drop // ドラッグされた要素がドロップ可能なターゲット上で放されたときにトリガーされます

これらのイベントの使い方を見てみましょう。

<!-- 要素リストのデータをドラッグ-->
<スクリプト>
// com は対応するビューコンポーネントであり、typeList はリリース領域に表示されます: {
 バナー:
  名前:「カルーセル」
  アイコン: 'el-icon-picture',
  com: バナー
 },
 製品: {
  名前: '製品',
  アイコン: 'el-icon-s-goods',
  com: 製品
 },
 画像:
  名前: '画像'、
  アイコン: 'el-icon-picture',
  com: 画像
 },
}
</スクリプト>
<!-- 要素をドラッグ -->
<ul 
 @dragstart="ドラッグスタート"
 @dragend="ドラッグ終了"
>
 <li 
  v-for="(val, key, index) in typeList"
  ドラッグ可能 
  :data-type="キー"
  :key="インデックス + 1"
 >
  <span :class="val.icon"></span>
  <p>{{val.name}}</p>
 </li>
</ul>
<!-- リリースエリア -->
<div 
 クラス="コンテンツを表示"
 @drop="ドロップ"
 @dragover="ドラッグオーバー"
>
</div>

ドラッグして開始

ドラッグ イベントの開始時に、製品、広告画像など、現在ドラッグされている要素のタイプを決定する変数タイプを定義します。

// ドラッグタイプ dragStart(e) {
 this.type = e.target.dataset.type
}

タイプを決定したら、リリースエリアの次のステップに進みます

リリースゾーンでの移動

移動プロセス中、ドラッグされた要素の位置は、マウスの位置に応じてリアルタイムで計算される必要があります。下にスクロールすると、アニメーション効果をプレビューできます。

// 'view-content': 外側のボックスのクラス、直接プッシュ
// 'item': ボックス内の要素。位置を計算し、変換操作を実行する必要があります。dragOver() {
 className = e.target.className とします。
 name = className !== 'view-content' ? 'item' : 'view-content' とします

 // コンポーネントのデフォルトデータ const defaultData = {
  type: this.type, // コンポーネント タイプ status: 2, // デフォルト ステータス data: [], // 基本データ options: {} // その他の操作 }

 if (name == 'view-content') {
  //...
 } そうでない場合 (名前 == 'アイテム') {
  //...
 }
}

境界処理、角度計算

コア変数:

  • isPush: ドラッグされた要素がページデータにプッシュされたかどうか
  • インデックス: ドラッグされた要素の最終インデックス値
  • curIndex: マウスが位置する要素のインデックス値
  • 方向: マウスが位置する要素の上部/下部

name=='view-content'の場合、ドラッグ要素が外側の空白の解放可能領域にあることを意味します。追加されていない場合は、直接プッシュしてください。

if (name == 'view-content') {
 if (!this.isPush) {
  this.index = this.view.length
  this.isPush = true
  this.view.push(デフォルトデータ)
 }
}

name=='item'、つまり既存の要素の上にある場合、位置、上/下、追加、移動を計算する必要があります。

if (名前 == 'アイテム') {
 ターゲット = e.target とする
 [ y, h, curIndex ] = [ e.offsetY, target.offsetHeight, target.dataset.index ] とします。
 let direction = y < (h / 2) // 現在の要素上のマウスの位置を計算して、ドラッグされた要素の上下方向を決定します。if (!this.isPush) {
  // 初め
  if (方向) {
   (現在のインデックス == 0) の場合 {
    this.view.unshift(デフォルトデータ)
   } それ以外 {
    this.view.splice(現在のインデックス、0、デフォルトデータ)
   }
  } それ以外 {
   現在のインデックス = +現在のインデックス + 1
   this.view.splice(現在のインデックス、0、デフォルトデータ)
  }
 } それ以外 {
  //移動中
  if (方向) {
   var i = curIndex == 0 ? 0 : curIndex - 1
   var 結果 = this.view[i]['ステータス'] == 2
  } それ以外 {
   var i = +現在のインデックス + 1
   var result = this.view.length > i && this.view[i]['status'] == 2
  }
  
  // ドラッグされた要素の位置を変更する必要があるかどうか if (result) return

  定数 temp = this.view.splice(this.index, 1)
  this.view.splice(curIndex, 0, temp[0])
 }
 this.index = curIndex // 要素の位置をドラッグします this.isPush = true // 入力する場合は押す、つまり true
}
  • 最初: 押されていない場合、ドラッグされた要素の位置は現在のインデックスと方向に基づいて決定されます
  • 移動: 押されて移動している状態。現在のインデックスと方向に応じて対応する値の状態を検索します。ドラッグされた要素の場合はそれを返し、そうでない場合は位置を変更します。

要約すると、マウスが現在位置する要素のインデックスを取得し、マウスが要素の上半分にあるか下半分にあるかを計算して、ドラッグされた要素の位置を推測します。 ! !

ちょっとした質問です:

上記の name=='item' では、ターゲットが内部要素になり、位置を計算できなくなるのを避けるために、Event イベントでデフォルト イベントをブロックする必要があります。ただし、イベント ブロックのみを使用すると、ここでは機能しません。理由はわかりません。.item のすべての子要素に、属性 pointer-events: none! を追加する必要があります。

e.preventDefault()
e.stopPropagation()

.item div{
 ポインタイベント: なし;
}

ドラッグ終了

マウスを離すか、リリースエリアから離れると、デフォルトの状態が復元されます。

ここでのステ​​ータスの役割は何でしょうか?

  1. 上記の計算ルールは、要素がドラッグ要素であるかどうかを判断するために使用されます。
  2. ページ表示モード: ドラッグ時にコンポーネント名のみが表示され、リリース後に通常の表示内容に戻ります。
// ドラッグ終了 dragEnd(e) {
 this.$delete(this.view[this.index], 'status')
 this.isPush = false
 this.type = null
},
// すでに指定された位置に配置されている drog(e) {
 e.preventDefault()
 e.stopPropagation()
 this.dragEnd()
},

コンテンツブロックのドラッグアンドドロップの実装

時間の制約のため、ここでは怠けて、より完璧なリストドラッグプラグイン Vue.Draggable (星 14.2k) を使用します。

しばらく勉強してみると、そのロジックは上で実装したドラッグアンドドロップと関連しており、具体的な実装方法も似ていることがわかりました。上記の実用的な例を使えば、あなたもできると思います!

あなたも試してみてはいかがでしょうか?

Vue.Draggable の使用に基づいてドラッグ コンポーネントを実装できます。これは、(ドラッグ、スロット、DOM) などの操作を使用します。

(時間があれば後で戻ってきてパッケージ化します)

コンポーネント部門

中央のビュー コンポーネントと右側の編集コンポーネントは、コンポーネントのセットです。予想どおり、コンポーネントのセットです。コンポーネントのセットである価値があります。

page=>indexはページ全体のコンテンツを管理します

。
├── コンポーネント
| ├── 編集 ## 右側で編集| | ├── 情報 # 基本情報| | ├── 画像 # 広告画像| | ├── 商品 # 商品| | └── インデックス # コンポーネント情報の管理と編集| └── 表示 ## 中央ビュー| | ├── バナー # スライドショー| | ├── 画像 # 広告画像| | └── 商品 # 商品一覧└── ページ
 └── インデックス ## メインページ

ページをプレビューする効果を得るには、components=>View の下のコンポーネントを使用するだけです。使い方は page=>index と同じなので、過度な変更は必要ありません。

データ構造の定義

明るく拡張可能な機能を実現するには、修飾されたデータ構造を定義することが不可欠です。同時に、コードの品質も判断できます。

もちろん、それはあなたが何を学んだか、そしてあなたの論理的思考力に依存します。

ここで最も目を引く処理方法は、オブジェクト間の関係を使用して、コンポーネント間の値の転送に一方向の送信のみが必要になるようにすることです。

ビュー: [
 {
  タイプ: '情報'、
  タイトル: 'ページタイトル',
  備考: 'ページの備考'、
  背景色: '赤'
 },
 {
  タイプ: 'バナー'、
  データ: [
   { url: '1.jpg'、名前: 'カルーセル画像1'、リンク: 'https://carousel image jump address.cn' },
   { url: '2.jpg'、名前: 'カルーセル 2'、リンク: 'https://carousel jump address.cn' }
  ]
 },
 {
  タイプ: '画像'、
  データ: [
   { url: '1.jpg', name: '広告画像1', link: 'https://広告画像ジャンプアドレス.cn' },
   { url: '2.jpg'、name: '広告画像2'、link: 'https://広告画像ジャンプアドレス.cn' }
  ]
 },
 {
  タイプ: '製品'、
  データ: [
   { id: '1'、名前: '製品 1'、画像: '1.jpg' }, 
   { id: '2'、名前: '製品 2'、画像: '2.jpg' }
  ]、
  オプション:
   originalPrice: true, // 取り消し線付き価格 goodRatio: true, // 好意的な評価 volumeStr: false, // 販売量}
 }
]

これは配列であり、配列内の項目はモジュールを表す。

  • タイプ: モジュールタイプ
  • データ: 基本情報
  • オプション: その他の操作

....オリジナルのコンポーネントモジュールを参考に、必要に応じて拡張することができます。

コンポーネント値を編集

ビューコンポーネントを選択するときに、ビューで指定されたアイテムオブジェクトをパラメーターとして編集コンポーネントに渡します。

オブジェクトは同じメモリ アドレスを指し、参照関係があります。多面的なデータ更新を実現するには、一度変更するだけで済みます。

<セクションクラス="r">
 <編集フォーム
  :data="プロパティ"
  v-if="isRight"
 </編集フォーム>
</セクション>
<スクリプト>
// ビューコンポーネントを切り替える selectType(index) {
 this.isRight = false
 this.props = this.view[インデックス]
 this.$nextTick(() => this.isRight = true)
}
</スクリプト>

画像アップロード

上に画像アップロードコンポーネントがあるので、ここで使用上のヒントを共有したいと思います。 !

Element-uiの組み込みアップロードコンポーネントを使用している友人は、ぜひご覧ください(黒板をたたきます)

まずは簡略化されたバージョンを実装してみましょう。

<!-- すべてのデフォルトメソッドを無効にする -->
<el-アップロード
 :http-request="アップロード"
 :ファイルリストを表示="false"
 複数
 アクション
>
 <img :src="item.url" v-for="(item, index) リスト内" :key="index">
</el-アップロード>
<スクリプト>
アップロード(パラメータ) {
 定数ファイル = params.file;
 定数フォーム = 新しい FormData();
 form.append("ファイル", ファイル);
 フォームに "clientType"、"multipart/form-data" を追加します。

 const index = this.imageIndex // 画像インデックスを編集する const data = { 
  url: URL.createObjectURL(ファイル)、 
  形状
 }
 if (インデックス !== null) {
  // this.list => 画像コレクション this.$set(this.list, index, data)
 } それ以外 {
  this.list.push(データ)
 }
}
</スクリプト>
  • アップロードメソッドを書き直す
  • URL.createObjectURL(file) を使用してローカルプレビューアドレスを作成します
  • フォームオブジェクトを保存し、送信時にアップロードします
// 上記のコードに従って、Promise を使用してアップロード機能を実装します。const request = []
this.list.forEach(item => {
 リクエスト.push(
  新しい Promise((resolve, 拒否) => {
   /**
    * アップロードインターフェース* 元のURLを置き換える
    * フォームを削除
    */
   imageUpload(item.form).then(res => {
    アイテム.url = res.data.url
    アイテムの削除フォーム
    解決する
   }).catch(エラー => {
    拒否(エラー)
   })
  })
 )
})
Promise.all(リクエスト).then(res => {
 // ... 提出する ...
})

最後のステップまで待ってデータを送信し、すべての写真をアップロードして、アップロードが完了したらデータを送信するためのインターフェイスを呼び出します。 !

複数のデータを送信するフォームがあるシナリオでは、これが最も正しいアプローチです。

最終まとめ

実際には、それは複雑ではありません。鍵となるのは、データ構造、コンポーネントの相互作用処理、論理的メソッドなどの計画です。このステップの核心点が達成されればそれで十分です。

新しいコンポーネントの追加、新しい操作の追加など、その他の拡張性操作については、残りの問題はもはや問題ではありません。

これはあくまでも簡易版として捉えることができます。必要に応じて最適化、熟考、改善し、自分の知識として吸収することができます。

少なくとも仕事の必要は満たされました、ハハハハハ〜〜〜

詳細はソースコードをご確認ください。こちらがGithubのアドレスです。星をありがとうございます。私はお茶を飲まない李白です。

以上が、Vue のビジュアル ドラッグ アンド ドロップ ページ エディターの実装の詳細です。Vue のビジュアル ドラッグ アンド ドロップ ページ エディターの詳細については、123WORDPRESS.COM の他の関連記事にも注目してください。

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

<<:  MySQL インストール プロンプト「詳細なヘルプについては NET HELPMSG 3534 と入力してください」の解決方法

>>:  nginx+uwsgi で Django プロジェクトを開始するための詳細な手順

推薦する

Centos 6.9 に MySQL をインストールするための詳細なチュートリアル

1. MySQLがインストールされているかどうかを確認します。次のコードで確認できます。 [root...

Linux CentOS 7.7 システムの VMware インストールに関する詳細なチュートリアル

Linux CentOS 7.7 システムを Vmware にインストールする方法。最小限のインスト...

18 個のキラー JavaScript ワンライナー

序文JavaScript は習得が最も簡単な言語の 1 つであるため、成長と繁栄を続けており、市場に...

ページングのどのページでMySQLのレコードをクエリするか

序文実際には、次のような問題に遭遇する可能性があります。特定のレコードの ID がわかっていて、その...

レスポンシブWebデザイン学習(3) - モバイルデバイスでのWebページのパフォーマンスを向上させる方法

序文モバイル デバイスでは、帯域幅とプロセッサ速度の制限により、Web ページのパフォーマンスに対す...

MySQL ページング分析の原理と効率改善

MySQL ページング分析の原理と効率改善PERCONA PERFORMANCE CONFERENC...

Nginx を使用して rtmp ライブ サーバーを実行する方法

今回は、コンピューターや携帯電話用の rtmp ライブ ブロードキャスト サーバーを設定し、ライブ ...

Azure Container Registry を使用してイメージを保存する際の問題

Azure Container Registry は、Docker Registry 2.0 仕様に...

Mac でソースコードから MySQL 5.7.17 をコンパイルしてインストールするチュートリアル

1. ダウンロードして解凍します: /Users/xiechunping/Softwares/mys...

MySQLのロック機構に関する最も包括的な説明

目次序文グローバルロック完全なデータベース論理バックアップFTWRL と set global re...

スクロールバーの美化効果を実現するための CSS3 のサンプル コード

具体的なコードは次のとおりです。 /*スクロールバーの幅*/ ::-webkit-スクロールバー{ ...

MySQL におけるデータベース間関連クエリメソッド

ビジネスシナリオ: 異なるデータベース内のテーブルをクエリするたとえば、関連付けられるテーブルは、マ...

Ubuntu 18.04 (コミュニティ エディション) に Docker CE をインストールする方法

古いバージョンをアンインストールする以前に古いバージョンをインストールしたことがある場合は、まずそれ...

Pagoda Panel のインストール時にサーバーがデータベースにリモート接続できない問題の解決策

自分のウェブサイトを構築する予定なので、618 プロモーションを利用して Tencent Cloud...

Apache での ModSecurity のインストール、有効化、および構成

ModSecurity は、Web サーバーに入るすべてのパケットをチェックする強力なパケット フィ...