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 のインストールと設定のグラフィックチュートリアル

推薦する

プロジェクトのフロントエンドとバックエンドでの Echart チャートの使用に関する詳細な説明

目次序文1. プロジェクトアーキテクチャ2. Echart公式サイトにアクセスして自己分析を学ぶ2....

Dockerボリュームのファイルマッピング方法

背景ブロックチェーン ログ モジュールで作業しているときに、コンテナーが実行されている場合は、ログ ...

Docker デプロイメント Springboot プロジェクト例の分析

この記事は主に、docker デプロイメント springboot プロジェクトのサンプル分析を紹介...

Vue+Openlayerはグラフィックスのドラッグと回転変形効果を実現します

目次序文関連資料成果を達成する実装手順序文Openlayer には独自の拡張プラグイン ol-ext...

同じドメイン名を持つ Nginx プロキシのフロントエンドとバックエンドの分離プロジェクトの完全な手順

フロントエンド プロジェクトとバックエンド プロジェクトは分離されており、フロントエンドとバックエン...

Vue プロジェクト @change 複数のパラメータを使用して複数のイベントを渡す

まず、変更イベントは 1 つだけです。 changelevel() //値を選択選択を変更して行の値...

Keras を使って SQL インジェクション攻撃を判断する (例の説明)

この記事では、ディープラーニングフレームワーク keras を使用して、SQL インジェクションの特...

CSS ロリポップを描くサンプルコード

背景: 毎日少しずつ進歩し、少しずつ積み重ねていけば、どんどん良くなっていきますコード: <!...

フレームセットを使用して複雑なページレイアウトを実装するためのテクニックの概要

コードをコピーコードは次のとおりです。 <html> <!--混合フレームレイアウ...

mysql5.7でbinlogを使用してデータを復元する方法

ステップ1: MySQLでbinlogが有効になっていることを確認する '%log_bin%...

Nginx ソースコード調査における nginx 電流制限モジュールの詳細な説明

目次1. 電流制限アルゴリズム2. nginxの基礎知識4. 実戦要約する高並行性システムには、キャ...

ページ要素の絶対位置と相対位置に関するある程度の理解

今日から、定期的にちょっとした豆知識を整理していきます。簡単なものもあるかもしれませんが、どれも役に...

DockerにTomcatコンテナを追加したときにホームページにアクセスできない問題の解決方法

質問docker run コマンドを使用して、tomcat コンテナが正常に追加されました。ポートも...

Docker を使用した nextcloud パーソナル ネットワーク ディスクの構築に関するチュートリアル

目次1. はじめに2. 導入環境ツール4. 展開プロセス要約する1. はじめにNextcloud は...

Centos7 での MySQL のインストールに関するチュートリアル

最近、自宅サーバーにクラウドディスクを導入する予定なので、一連の環境構築作業を始めました。MySQL...