Vueコンポーネントの再利用と拡張の詳細な説明

Vueコンポーネントの再利用と拡張の詳細な説明

概要

ソフトウェア プログラミングにおける重要な原則は DRY (Don't Repeat Yourself) です。これは、コードとロジックを可能な限り再利用して重複を減らすことです。コンポーネント拡張により、コードの重複を回避し、開発と保守を迅速に行うことができます。では、Vue コンポーネントを拡張する最良の方法は何でしょうか?

Vue は、コンポーネントの再利用と拡張をサポートするために、多数の API とパターンを提供しています。目的や好みに応じて選択できます。

この記事では、いくつかの一般的な方法とパターンを紹介します。お役に立てば幸いです。

延長は必要ですか?

すべてのコンポーネント拡張メソッドにより、複雑さや余分なコードが追加され、場合によってはパフォーマンスのオーバーヘッドが増加することに注意してください。

したがって、コンポーネントを拡張することを決定する前に、目的を達成できる他のよりシンプルな設計パターンがあるかどうかを確認することをお勧めします。

通常、拡張コンポーネントを置き換えるには、次のコンポーネント設計パターンで十分です。

  • テンプレートロジックを持つプロパティ
  • スロット
  • JavaScript ユーティリティ関数

テンプレートロジックを持つプロパティ

最も簡単な方法は、コンポーネントの多機能性を実現するために、テンプレートの条件付きレンダリングと組み合わせてプロパティを使用することです。

たとえば、type 属性を使用すると次のようになります。
私の多用途コンポーネント.vue

<テンプレート>
  <div class="wrapper">
    <div v-if="type === 'a'">...</div>
    <div v-else-if="type === 'b'">...</div>
    <!--などなど-->
  </div>
</テンプレート>
<スクリプト>
エクスポートデフォルト{
  プロパティ: { 型: 文字列 },
  ...
}
</スクリプト>

コンポーネントを使用する場合、異なる型の値を渡すと、異なる結果が得られます。

// *親コンポーネント.vue*
<テンプレート>
  <MyVersatileComponent タイプ="a" />
  <MyVersatileComponent タイプ="b" />
</テンプレート>

次の 2 つの状況が発生する場合、このモードは適用できないか、または誤って使用されていることを意味します。

  • コンポーネント構成パターンは、状態とロジックをアトミックな部分に分解し、アプリケーションをスケーラブルにします。コンポーネント内に条件判断が多いと、可読性や保守性が悪くなります。
  • props とテンプレート ロジックの本来の目的はコンポーネントを動的にすることですが、実行時にリソースが消費されることもあります。このメカニズムを使用して実行時にコード構成の問題を解決すると、それはアンチパターンになります。

スロット

コンポーネント拡張を回避するもう 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 のモジュール システムは、コードを共有するための非常に柔軟で堅牢な方法であるため、可能な限りこれに頼る必要があります。
マイユーティリティ関数.js

エクスポートデフォルト関数(){
  ...
}

私のコンポーネント.vue

MyUtilityFunction を "./MyUtilityFunction" からインポートします。
エクスポートデフォルト{
  メソッド: {
    マイユーティリティ関数
  }
}

拡張コンポーネントの複数のモード

上記のシンプルなモードを検討したが、これらのモードはニーズを満たすほど柔軟ではない場合。次に、コンポーネントの拡張を検討できます。

Vue コンポーネントを拡張する最も一般的な方法は 4 つあります。

  • 合成機能
  • ミックスイン
  • 高階コンポーネント (HOC)
  • レンダリングコンポーネントなし

それぞれの方法には長所と短所があり、使用シナリオに応じてそれぞれの方法が多かれ少なかれ適用可能になります。

コンポジションAPI

コンポーネント間で状態とロジックを共有するための最新のアプローチは、Composition API です。これは Vue 3 で導入された API であり、Vue 2 ではプラグインとしても使用できます。

コンポーネント定義構成オブジェクトでデータ、計算、メソッド、およびその他のプロパティを宣言する以前の方法とは異なり、Composition API はセットアップ関数を通じてこれらの構成を宣言し、返します。

たとえば、Vue 2 構成プロパティを使用してCounterコンポーネントを宣言すると、次のようになります。
カウンター.vue

<テンプレート>
  <ボタン @click="増加">
    カウントは: {{ count }}、double は: {{ double }}
  </ボタン>
<テンプレート>
<スクリプト>
エクスポートデフォルト{
  データ: () => ({
    カウント: 0
  })、
  メソッド: {
    インクリメント() {
      this.count++;
    }
  },
  計算: {
    ダブル(){
      this.count * 2 を返します。
    }
  }
}
</スクリプト>

Composition API を使用してこのコンポーネントをリファクタリングすると、まったく同じ機能が得られます。
カウンター.vue

<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 コンポーネントにシームレスに導入できるようになりました。
MyComponent.vue

<template><!--上記の通り--></template>
<スクリプト>
「./useCounter」からuseCounterをインポートします。

エクスポートデフォルト{
  設定() {
    const { count, double, increment } = useCounter();
    戻る {
      カウント、
      ダブル、
      インクリメント
    }
  }
}
</スクリプト>

合成関数は関数をモジュール化して再利用可能にし、コンポーネントを拡張するための最も直接的で低コストの方法です。

コンポジションAPIの欠点

Composition API の欠点はそれほど大きくありません。少し冗長に見えるかもしれないし、新しい慣用句が一部の Vue 開発者にとって馴染みのないものであるかもしれないだけです。

Composition API の長所と短所については、「新しい Vue Composition API を使用する場合 (および使用しない場合)」をお読みください。

ミックスイン

まだ Vue 2 を使用している場合、またはコンポーネント関数を構成オブジェクトとして定義したい場合は、ミックスイン モードを使用できます。ミックスインは、共通のロジックと状態を個別のオブジェクトに抽出し、ミックスインを使用するコンポーネント内で定義されたオブジェクトとマージします。

前のCounterコンポーネントの例を引き続き使用し、共通のロジックと状態をCounterMixin.jsモジュールに配置します。
カウンターミックスイン.js

エクスポートデフォルト{
  データ: () => ({
    カウント: 0
  })、
  メソッド: {
    インクリメント() {
      this.count++;
    }
  },
  計算: {
    ダブル(){
      this.count * 2 を返します。
    }
  }
}

ミックスインの使用も非常に簡単で、対応するモジュールをインポートし、変数をミックスイン配列に追加するだけです。コンポーネントが初期化されると、ミックスイン オブジェクトはコンポーネント内で定義されたオブジェクトとマージされます。
私のコンポーネント.vue

「./CounterMixin」からCounterMixinをインポートします。

エクスポートデフォルト{
  ミックスイン: [CounterMixin],
  メソッド: {
    減算() {
      this.count--;
    }
  }
}

オプションのマージ

コンポーネント内のオプションがミックスインと競合する場合はどうなりますか?

たとえば、コンポーネントに組み込みの増分メソッドを定義する場合、どちらの方が優先度が高いでしょうか?
MyComponent.vue

「./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 つのプロパティを親コンポーネントに公開します。
カウンターレンダーレス.js

エクスポートデフォルト{
  データ: () => ({
    カウント: 0
  })、
  メソッド: {
    インクリメント() {
      this.count++;
    }
  },
  計算: {
    ダブル(){
      this.count * 2 を返します。
    }
  },
  与える() {
    this.$scopedSlots.default({ を返します。
      カウント: this.count,
      ダブル: this.double,
      増分: this.toggleState、
    })
  }
}

ここでのスコープ スロットは、このパターンのロジック コンポーネントの鍵となります。

プレゼンテーションコンポーネント

次は表示コンポーネントです。これは、レンダリングレス コンポーネントのユーザーとして、特定の表示方法を提供します。

すべての要素タグはスコープ付きスロットに含まれます。ご覧のとおり、これらのプロパティは、テンプレートがロジック コンポーネントに直接配置されている場合と同じように使用されます。
カウンター付きボタン.vue

<テンプレート>
  <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 プラグインをインストールする必要があります。次に、ベース テンプレートをインポートし、ブロック入力構文を使用してプレースホルダーを置き換えることができます。
私のコンポーネント.vue

<テンプレート lang="pug">
  BaseTemplate.pug を拡張します
  ブロック入力
    h4 {{ myLocalProp }} <!-- ベーステンプレートに含まれます -->
</テンプレート>

最初はスロットと同じ概念だと思うかもしれませんが、違いがあります。ここでの基本テンプレートは、個々のコンポーネントに属していません。スロットのように実行時に置き換えられるのではなく、コンパイル時に現在のコンポーネントとマージされます。

以上がVueコンポーネントの再利用と拡張についての詳しい説明です。Vueコンポーネントの再利用と拡張についての詳細は、123WORDPRESS.COM内の他の関連記事にも注目してください!

以下もご興味があるかもしれません:
  • Vueコンポーネントは複数のカスタムパラメータ操作を再利用します
  • vue-router コンポーネント再利用問題の詳細な説明
  • Vue ミックスイン コンポーネントを再利用するいくつかの方法 (要約)
  • Vueはコンポーネントの再利用可能な機能を配布するためにミックスインを使用します
  • Vue.jsの再利用コンポーネント開発プロセスの完全記録
  • Vueコンポーネントと再利用の詳細な説明
  • 再利用可能なコンポーネントメソッドをVueにカプセル化する
  • Vue2.0コンポーネントの継承と拡張の詳細な説明
  • VUE の element-ui における ElTableColumn の拡張の詳細な説明

<<:  Linux で開いているポートへのリモート アクセスを許可する方法

>>:  Ubuntu Server 16.04 MySQL 8.0 のインストールと設定のグラフィックチュートリアル

推薦する

Nginx を使用して https ルートドメイン名への 301 リダイレクトを実装するためのサンプル コード

SEO とセキュリティを考慮して、301 リダイレクトが必要です。以下の一般的な処理には Nginx...

CentOS7 構成 Alibaba Cloud yum ソースメソッドコード

Centos yumフォルダを開くコマンドcd /etc/yum.repos.d/を入力します。 w...

SQL実装 LeetCode (176. 2番目に高い給与)

[LeetCode] 176. 2番目に高い給与従業員テーブルから 2 番目に高い給与を取得する ...

JavaScript を使用して文字列内の最も繰り返しの多い文字を取得する方法

目次トピック分析する使用目的解決:コードは次のように実装されます。分析:配列とポインタ解決:コードは...

レスポンシブウェブデザインを実現するためにIEでCSS3メディアクエリをサポートする

今日の画面解像度は、320 ピクセル (iPhone) ほど小さいものから、2560 ピクセル以上 ...

JavaScript スコープチェーンの基本原理のグラフィカルな説明

目次序文範囲1. スコープとは何ですか? 2. [[スコープ]] プロパティ3. スコープチェーン4...

Hadoop を使用せずに Linux 環境に Spark のスタンドアロン バージョンをインストールする方法

ビッグデータはますます注目を集めており、ビッグデータのいくつかの構成要素に精通していないと、自慢でき...

MySQL パフォーマンス最適化インデックス プッシュダウン

インデックス条件プッシュダウン (ICP) は MySQL 5.6 で導入され、クエリを最適化するた...

Docker で Nginx イメージ サーバーを構築する方法

序文一般的な開発では、画像をディレクトリにアップロードし、ディレクトリとファイル名を連結してデータベ...

Linux マルチスレッドにおけるフォークとミューテックス ロック プロセスの例

目次質問: 1. 最初の試み2. 合理的な分析3. 問題解決(1) pthread_join()の使...

vue+echartsチャートの使用に関する問題記録

序文echarts は私が最もよく使用するチャート作成ツールであり、非常に完全なエコシステムとコンテ...

CSS でホバー ドロップダウン メニューを実装する方法

いつものように、今日は非常に実用的な CSS 効果についてお話します。マウスがボタンに移動すると、ド...

モバイル アプリのユーザー インターフェース設計に関する 10 のヒント

ヒント1: 集中力を保つ最高のモバイル アプリは、1 つのことを非常にうまく行うことに重点を置いてい...

JS 継承の詳細

目次序文準備する要約する継承方法プロトタイプ継承プロトタイプチェーン継承コンストラクタの借用(クラス...

CSS3 クリックボタン円形進行ティック効果実装コード

目次8. CSS3 クリックボタンの円形進捗チェック効果8.1 画像プレビュー8.2 index.h...