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

推薦する

MySQL トランザクションの概念と使用法の詳細な説明

目次情事の概念取引の状態取引の役割取引の特徴トランザクション構文トランザクション対応ストレージエンジ...

ウェブサイト開発におけるフロントエンド開発者とアーティストの知識の違い

概要: 多くの企業、特にインターネット Web サイトを主な事業とする企業のほとんどが、「アーティス...

SSL を実装するために nginx を設定する方法の例

環境説明サーバーシステム: Ubuntu 18.04 64ビットnginx: 1.14この記事では主...

ユニアプリとミニプログラム(画像とテキスト)を下請けする方法を教えます

目次1. ミニプログラム下請け2. Uniapp 下請けアプレット下請けの手順: 1. manife...

Django がローカル MySQL データベースに接続する手順 (pycharm)

ステップ1:setting.pyでデータベースを変更する # データベースを構成する DATABAS...

...

Linux (Ubuntu) での MySQL 5.7.17 のインストールと設定のチュートリアル

序文以前、MySQL 5.6 をインストールしました。3 か月後、開発者から MySQL で JSO...

OEL7.6 ソースコードから MYSQL5.7 をインストールするチュートリアル

まず、公式サイト https://dev.mysql.com/downloads/mysql/5.7...

MySQL でグループ化した後、各グループの最大値を取得する詳細な例

MySQL でグループ化した後、各グループの最大値を取得する詳細な例1. テストデータベーステーブル...

背景のグラデーションと自動フルスクリーンを実現するCSSコード

背景グラデーションと自動フルスクリーンに関する CSS の問題編集長は CSS の開発中に致命的な問...

Linux ログ表示方法 6 つのまとめ

バックエンド プログラマーは、さまざまな場所で Linux を扱います。Linux ログの読み方がわ...

vscode を使用したリモート Linux 開発の実装

過去に別れを告げるvscode にリモート SSH が導入される前は、Linux サーバー開発者の多...

Nodejs でタイムドクローラーを実装する完全な例

目次事件の原因Node Scheduleを使用してスケジュールされたタスクを実装する1. node-...

Excel をインポートするときに js で時間を変換する正しい方法について

目次1. 基本2. 問題の説明3. 解決策付録: js を使用して Excel の日付形式を変換する...

Vue echarts は水平棒グラフを実現します

この記事では、水平棒グラフを実現するためのvue echartsの具体的なコードを参考までに共有しま...