オンラインアドレス(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') { //... } そうでない場合 (名前 == 'アイテム') { //... } } 境界処理、角度計算コア変数:
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{ ポインタイベント: なし; } ドラッグ終了マウスを離すか、リリースエリアから離れると、デフォルトの状態が復元されます。 ここでのステータスの役割は何でしょうか?
// ドラッグ終了 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(データ) } } </スクリプト>
// 上記のコードに従って、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 の他の関連記事にも注目してください。 以下もご興味があるかもしれません:
|
<<: MySQL インストール プロンプト「詳細なヘルプについては NET HELPMSG 3534 と入力してください」の解決方法
>>: nginx+uwsgi で Django プロジェクトを開始するための詳細な手順
1. MySQLがインストールされているかどうかを確認します。次のコードで確認できます。 [root...
Linux CentOS 7.7 システムを Vmware にインストールする方法。最小限のインスト...
序文JavaScript は習得が最も簡単な言語の 1 つであるため、成長と繁栄を続けており、市場に...
序文実際には、次のような問題に遭遇する可能性があります。特定のレコードの ID がわかっていて、その...
序文モバイル デバイスでは、帯域幅とプロセッサ速度の制限により、Web ページのパフォーマンスに対す...
MySQL ページング分析の原理と効率改善PERCONA PERFORMANCE CONFERENC...
今回は、コンピューターや携帯電話用の rtmp ライブ ブロードキャスト サーバーを設定し、ライブ ...
Azure Container Registry は、Docker Registry 2.0 仕様に...
1. ダウンロードして解凍します: /Users/xiechunping/Softwares/mys...
目次序文グローバルロック完全なデータベース論理バックアップFTWRL と set global re...
具体的なコードは次のとおりです。 /*スクロールバーの幅*/ ::-webkit-スクロールバー{ ...
ビジネスシナリオ: 異なるデータベース内のテーブルをクエリするたとえば、関連付けられるテーブルは、マ...
古いバージョンをアンインストールする以前に古いバージョンをインストールしたことがある場合は、まずそれ...
自分のウェブサイトを構築する予定なので、618 プロモーションを利用して Tencent Cloud...
ModSecurity は、Web サーバーに入るすべてのパケットをチェックする強力なパケット フィ...