概要ソフトウェア プログラミングにおける重要な原則は DRY (Don't Repeat Yourself) です。これは、コードとロジックを可能な限り再利用して重複を減らすことです。コンポーネント拡張により、コードの重複を回避し、開発と保守を迅速に行うことができます。では、Vue コンポーネントを拡張する最良の方法は何でしょうか? Vue は、コンポーネントの再利用と拡張をサポートするために、多数の API とパターンを提供しています。目的や好みに応じて選択できます。 この記事では、いくつかの一般的な方法とパターンを紹介します。お役に立てば幸いです。 延長は必要ですか?すべてのコンポーネント拡張メソッドにより、複雑さや余分なコードが追加され、場合によってはパフォーマンスのオーバーヘッドが増加することに注意してください。 したがって、コンポーネントを拡張することを決定する前に、目的を達成できる他のよりシンプルな設計パターンがあるかどうかを確認することをお勧めします。 通常、拡張コンポーネントを置き換えるには、次のコンポーネント設計パターンで十分です。
テンプレートロジックを持つプロパティ 最も簡単な方法は、コンポーネントの多機能性を実現するために、テンプレートの条件付きレンダリングと組み合わせてプロパティを使用することです。 たとえば、type 属性を使用すると次のようになります。 <テンプレート> <div class="wrapper"> <div v-if="type === 'a'">...</div> <div v-else-if="type === 'b'">...</div> <!--などなど--> </div> </テンプレート> <スクリプト> エクスポートデフォルト{ プロパティ: { 型: 文字列 }, ... } </スクリプト> コンポーネントを使用する場合、異なる型の値を渡すと、異なる結果が得られます。 // *親コンポーネント.vue* <テンプレート> <MyVersatileComponent タイプ="a" /> <MyVersatileComponent タイプ="b" /> </テンプレート> 次の 2 つの状況が発生する場合、このモードは適用できないか、または誤って使用されていることを意味します。
スロットコンポーネント拡張を回避するもう 1 つの方法は、スロットを使用することです。これにより、親コンポーネントが子コンポーネントにカスタム コンテンツを設定できるようになります。 // *MyVersatileComponent.vue* <テンプレート> <div class="wrapper"> <h3>共通マークアップ</div> <スロット /> </div> </テンプレート> // *親コンポーネント.vue* <テンプレート> <MyVersatileComponent> <h4>スロットに挿入する</h4> </MyVersatileComponent> </テンプレート> レンダリング結果: <div class="wrapper"> <h3>共通マークアップ</div> <h4>スロットに挿入する</h4> </div> このパターンの潜在的な制約の 1 つは、スロット内の要素が親コンポーネントのコンテキストに従属することであり、これはロジックと状態を分割するときに自然ではない可能性があります。スコープ スロットはより柔軟性が高く、レンダリングなしのコンポーネントのセクションで後ほど説明します。 JavaScript ユーティリティ関数コンポーネント間で独立した関数を再利用するだけの場合は、これらの JavaScript モジュールを抽出するだけでよく、コンポーネント拡張モードを使用する必要はありません。 JavaScript のモジュール システムは、コードを共有するための非常に柔軟で堅牢な方法であるため、可能な限りこれに頼る必要があります。 エクスポートデフォルト関数(){ ... } 私のコンポーネント.vue MyUtilityFunction を "./MyUtilityFunction" からインポートします。 エクスポートデフォルト{ メソッド: { マイユーティリティ関数 } } 拡張コンポーネントの複数のモード上記のシンプルなモードを検討したが、これらのモードはニーズを満たすほど柔軟ではない場合。次に、コンポーネントの拡張を検討できます。 Vue コンポーネントを拡張する最も一般的な方法は 4 つあります。
それぞれの方法には長所と短所があり、使用シナリオに応じてそれぞれの方法が多かれ少なかれ適用可能になります。 コンポジションAPIコンポーネント間で状態とロジックを共有するための最新のアプローチは、Composition API です。これは Vue 3 で導入された API であり、Vue 2 ではプラグインとしても使用できます。 コンポーネント定義構成オブジェクトでデータ、計算、メソッド、およびその他のプロパティを宣言する以前の方法とは異なり、Composition API はセットアップ関数を通じてこれらの構成を宣言し、返します。 たとえば、Vue 2 構成プロパティを使用してCounterコンポーネントを宣言すると、次のようになります。 <テンプレート> <ボタン @click="増加"> カウントは: {{ count }}、double は: {{ double }} </ボタン> <テンプレート> <スクリプト> エクスポートデフォルト{ データ: () => ({ カウント: 0 })、 メソッド: { インクリメント() { this.count++; } }, 計算: { ダブル(){ this.count * 2 を返します。 } } } </スクリプト> Composition API を使用してこのコンポーネントをリファクタリングすると、まったく同じ機能が得られます。 <template><!--上記の通り--><template> <スクリプト> 「vue」から { reactive, computed } をインポートします。 エクスポートデフォルト{ 設定() { 定数状態 = リアクティブ({ カウント: 0, ダブル: 計算された(() => state.count * 2) }); 関数の増分() { 状態.count++ } 戻る { カウント、 ダブル、 インクリメント } } } </スクリプト> Composition API を使用してコンポーネントを宣言する主な利点の 1 つは、ロジックの再利用と抽出が非常に簡単になることです。 さらにリファクタリングして、カウンター機能を JavaScript モジュール useCounter.js に移動しましょう。 「vue」から { reactive, computed } をインポートします。 デフォルト関数をエクスポートする{ 定数状態 = リアクティブ({ カウント: 0, ダブル: 計算された(() => state.count * 2) }); 関数の増分() { 状態.count++ } 戻る { カウント、 ダブル、 インクリメント } } これで、カウンター機能は、セットアップ関数を通じて任意の Vue コンポーネントにシームレスに導入できるようになりました。 <template><!--上記の通り--></template> <スクリプト> 「./useCounter」からuseCounterをインポートします。 エクスポートデフォルト{ 設定() { const { count, double, increment } = useCounter(); 戻る { カウント、 ダブル、 インクリメント } } } </スクリプト> 合成関数は関数をモジュール化して再利用可能にし、コンポーネントを拡張するための最も直接的で低コストの方法です。 コンポジションAPIの欠点 Composition API の欠点はそれほど大きくありません。少し冗長に見えるかもしれないし、新しい慣用句が一部の Vue 開発者にとって馴染みのないものであるかもしれないだけです。 Composition API の長所と短所については、「新しい Vue Composition API を使用する場合 (および使用しない場合)」をお読みください。 ミックスインまだ Vue 2 を使用している場合、またはコンポーネント関数を構成オブジェクトとして定義したい場合は、ミックスイン モードを使用できます。ミックスインは、共通のロジックと状態を個別のオブジェクトに抽出し、ミックスインを使用するコンポーネント内で定義されたオブジェクトとマージします。 前のCounterコンポーネントの例を引き続き使用し、共通のロジックと状態をCounterMixin.jsモジュールに配置します。 エクスポートデフォルト{ データ: () => ({ カウント: 0 })、 メソッド: { インクリメント() { this.count++; } }, 計算: { ダブル(){ this.count * 2 を返します。 } } } ミックスインの使用も非常に簡単で、対応するモジュールをインポートし、変数をミックスイン配列に追加するだけです。コンポーネントが初期化されると、ミックスイン オブジェクトはコンポーネント内で定義されたオブジェクトとマージされます。 「./CounterMixin」からCounterMixinをインポートします。 エクスポートデフォルト{ ミックスイン: [CounterMixin], メソッド: { 減算() { this.count--; } } } オプションのマージ コンポーネント内のオプションがミックスインと競合する場合はどうなりますか? たとえば、コンポーネントに組み込みの増分メソッドを定義する場合、どちらの方が優先度が高いでしょうか? 「./CounterMixin」からCounterMixinをインポートします。 エクスポートデフォルト{ ミックスイン: [CounterMixin], メソッド: { // ネイティブの `increment`` メソッドはミックスインの `increment` をオーバーライドしますか? 増分() { ... } } } 今回は、Vue のマージ戦略について話す必要があります。 Vue には、同じ名前のオプションをどのように処理するかを決定する一連のルールがあります。 通常、コンポーネント オプションはミックスインからのオプションをオーバーライドします。ただし、例外もあります。たとえば、同じタイプのライフサイクルフックは直接上書きされるのではなく、配列に格納されて順番に実行されます。 カスタムマージ戦略を定義してデフォルトの動作を変更することもできます。 ミックスインの欠点 コンポーネントを拡張するパターンとして、mixin は単純なシナリオではうまく機能しますが、規模が拡大すると問題が発生します。名前の競合(特にサードパーティのミックスインの場合)に注意する必要があるだけでなく、複数のミックスインを持つコンポーネントを使用する場合、特定の機能がどこから来ているのかを把握するのが難しく、問題の場所を特定することも困難です。 高階コンポーネント高階コンポーネント (HOC) は React から借用した概念であり、Vue でも使用できます。 この概念を理解するために、コンポーネントから離れて、2 つの単純な JavaScript 関数、increment と double を見てみましょう。 関数の増分(x) { x++ を返します。 } 関数 double(x) { x * 2 を返します。 } 両方の関数に、コンソールに結果を出力する機能を追加したいとします。 これを行うには、高階関数パターンを使用して、関数をパラメーターとして受け入れ、追加された機能を持つ関数を返す新しい addLogging 関数を作成します。 関数addLogging(fn) { 関数(x)を返す{ 定数結果 = fn(x); console.log("結果は: ", result); 結果を返します。 }; } 定数 incrementWithLogging = addLogging(増分); 定数 doubleWithLogging = addLogging(double); コンポーネントはこのパターンをどのように活用できるでしょうか?同様に、 Counterコンポーネントをレンダリングするための高階コンポーネントを作成し、インスタンス プロパティとしてデクリメント メソッドを追加します。 実際のコードはもっと複雑なので、ここでは例として疑似コードのみを示します。 「./Counter」からCounterをインポートします。 // 疑似コード const CounterWithDecrement => ({ レンダリング(要素を作成) { 定数オプション = { 減算() { this.count--; } } createElement(Counter, options) を返します。 } }); HOC モードは mixin よりもシンプルで拡張性に優れていますが、ラッパー コンポーネントを追加する必要があり、実装にもスキルが必要です。 レンダリングコンポーネントなし複数のコンポーネントで同じロジックと状態を使用する必要があり、それらを異なる方法で表示するだけの場合は、レンダリングレス コンポーネントパターンを検討できます。 このパターンには、ロジックコンポーネントはロジックと状態を宣言するために使用され、プレゼンテーションコンポーネントはデータを表示するために使用されます。 ロジックコンポーネント Counter の例に戻りましょう。このコンポーネントを複数の場所で再利用し、異なる方法で表示する必要があるとします。 CounterRenderless.js を作成して、ロジックと状態を含む論理コンポーネントを定義しますが、テンプレートは使用しません。代わりに、レンダリング関数を使用してスコープ スロットを宣言します。 スコープ スロットは、状態カウント、メソッドの増分、および計算プロパティ double の 3 つのプロパティを親コンポーネントに公開します。 エクスポートデフォルト{ データ: () => ({ カウント: 0 })、 メソッド: { インクリメント() { this.count++; } }, 計算: { ダブル(){ this.count * 2 を返します。 } }, 与える() { this.$scopedSlots.default({ を返します。 カウント: this.count, ダブル: this.double, 増分: this.toggleState、 }) } } ここでのスコープ スロットは、このパターンのロジック コンポーネントの鍵となります。 プレゼンテーションコンポーネント 次は表示コンポーネントです。これは、レンダリングレス コンポーネントのユーザーとして、特定の表示方法を提供します。 すべての要素タグはスコープ付きスロットに含まれます。ご覧のとおり、これらのプロパティは、テンプレートがロジック コンポーネントに直接配置されている場合と同じように使用されます。 <テンプレート> <counter-renderless slot-scope="{ count, double, increment }"> <div>カウントは: {{ count }} です。}</div> <div>Double は: {{ double }}</div> <button @click="increment">増加</button> </counter-renderless> </テンプレート> <スクリプト> 「./CountRenderless」からCounterRenderlessをインポートします。 エクスポートデフォルト{ コンポーネント: カウンターレンダリングレス } } </スクリプト> レンダリングレス コンポーネント パターンは非常に柔軟で理解しやすいです。ただし、これは以前の方法ほど汎用的ではなく、コンポーネント ライブラリを開発するという 1 つのアプリケーション シナリオのみになる可能性があります。 テンプレート拡張上記の API とデザイン パターンには、コンポーネント テンプレートを拡張できないという制限があります。 Vue にはロジックと状態を再利用する手段がありますが、テンプレート タグに関しては無力です。 よりハッキーな方法として、Pug などの HTML プリプロセッサを使用してテンプレートの拡張を処理する方法もあります。 最初のステップは、共通のページ要素を含む基本テンプレート.pugファイルを作成することです。テンプレート拡張のプレースホルダーとしてブロック入力も含めます。 ベーステンプレート.pug div.ラッパー h3 {{ myCommonProp }} <!--共通マークアップ--> ブロック入力 <!--拡張マークアップ アウトレット --> このテンプレートを拡張するには、Vue Loader 用の Pug プラグインをインストールする必要があります。次に、ベース テンプレートをインポートし、ブロック入力構文を使用してプレースホルダーを置き換えることができます。 <テンプレート lang="pug"> BaseTemplate.pug を拡張します ブロック入力 h4 {{ myLocalProp }} <!-- ベーステンプレートに含まれます --> </テンプレート> 最初はスロットと同じ概念だと思うかもしれませんが、違いがあります。ここでの基本テンプレートは、個々のコンポーネントに属していません。スロットのように実行時に置き換えられるのではなく、コンパイル時に現在のコンポーネントとマージされます。 以上がVueコンポーネントの再利用と拡張についての詳しい説明です。Vueコンポーネントの再利用と拡張についての詳細は、123WORDPRESS.COM内の他の関連記事にも注目してください! 以下もご興味があるかもしれません:
|
<<: Linux で開いているポートへのリモート アクセスを許可する方法
>>: Ubuntu Server 16.04 MySQL 8.0 のインストールと設定のグラフィックチュートリアル
SEO とセキュリティを考慮して、301 リダイレクトが必要です。以下の一般的な処理には Nginx...
Centos yumフォルダを開くコマンドcd /etc/yum.repos.d/を入力します。 w...
[LeetCode] 176. 2番目に高い給与従業員テーブルから 2 番目に高い給与を取得する ...
目次トピック分析する使用目的解決:コードは次のように実装されます。分析:配列とポインタ解決:コードは...
今日の画面解像度は、320 ピクセル (iPhone) ほど小さいものから、2560 ピクセル以上 ...
目次序文範囲1. スコープとは何ですか? 2. [[スコープ]] プロパティ3. スコープチェーン4...
ビッグデータはますます注目を集めており、ビッグデータのいくつかの構成要素に精通していないと、自慢でき...
インデックス条件プッシュダウン (ICP) は MySQL 5.6 で導入され、クエリを最適化するた...
序文一般的な開発では、画像をディレクトリにアップロードし、ディレクトリとファイル名を連結してデータベ...
目次質問: 1. 最初の試み2. 合理的な分析3. 問題解決(1) pthread_join()の使...
序文echarts は私が最もよく使用するチャート作成ツールであり、非常に完全なエコシステムとコンテ...
いつものように、今日は非常に実用的な CSS 効果についてお話します。マウスがボタンに移動すると、ド...
ヒント1: 集中力を保つ最高のモバイル アプリは、1 つのことを非常にうまく行うことに重点を置いてい...
目次序文準備する要約する継承方法プロトタイプ継承プロトタイプチェーン継承コンストラクタの借用(クラス...
目次8. CSS3 クリックボタンの円形進捗チェック効果8.1 画像プレビュー8.2 index.h...