Vueコンポーネントの7つの通信方法についての深い理解

Vueコンポーネントの7つの通信方法についての深い理解

Vue コンポーネントの通信方法は、面接で非常に頻繁に聞かれる質問です。インターンシップを探し始めた頃、私はこの質問によく遭遇しました。当時は、props と $emit に戻ることしか知りませんでした。その後、もっと学ぶにつれて、Vue コンポーネントが通信する方法はたくさんあることがわかりました。

今日はVueコンポーネントの通信方法についてまとめます。抜けがあればメッセージを残してください。

1. props/$emit

導入

最も一般的に使用される Vue 通信方法である props と $emit については、皆さんもよくご存知だと思います。

props: props は配列またはオブジェクトであり、v-bind を介して親コンポーネントから渡されるデータを受け取るために使用されます。 props が配列の場合、親コンポーネントから渡されたプロパティが直接受け取られます。props がオブジェクトの場合、type、default、required、validator などの構成を通じて、プロパティの型、デフォルト値、必須かどうか、検証ルールを設定できます。

$emit: 親子コンポーネントが通信する場合、通常は $emit を使用して親コンポーネントの v-on をトリガーし、子コンポーネントの対応するイベント リスナーをバインドします。

コードサンプル

次のコードは、props と $emit の親子コンポーネント通信を実装します。この例では、次の通信を実装しました。

親から子への値の受け渡し: 親コンポーネントは、messageFromParent="message" を通じて、親コンポーネントのメッセージ値を子コンポーネントに渡します。親コンポーネントの input タグが入力されると、子コンポーネントの p タグの内容がそれに応じて変更されます。

子から親への値の受け渡し: 親コンポーネントは、@on-receive="receive" を通じて、受信イベントのリスナーを子コンポーネントにバインドします。子コンポーネントの input タグが入力されると、受信コールバック関数がトリガーされます。子コンポーネントの message の値は、this.$emit('on-receive', this.message) を通じて親コンポーネントの messageFromChild に割り当てられ、親コンポーネントの p タグの内容が変更されます。

コードをご覧ください:

// サブコンポーネントコード <テンプレート>
  <div class="child">
    <h4>これは子コンポーネントです</h4>
    <input type="text" v-model="message" @keyup="send" />
    <p>親コンポーネントからメッセージを受信しました: {{ messageFromParent }}</p>
  </div>
</テンプレート>
<スクリプト>
エクスポートデフォルト{
  名前: 「子供」
  props: ['messageFromParent'], // props data() を通じて親コンポーネントからメッセージを受信します {
    戻る {
      メッセージ: ''、
    }
  },
  メソッド: {
    送信() {
      this.$emit('on-receive', this.message) // $emit を通じて on-receive イベントをトリガーし、親コンポーネントで受信コールバックを呼び出し、this.message をパラメータとして使用します},
  },
}
</スクリプト>
// 親コンポーネントコード <テンプレート>
  <div class="parent">
    <h3>これは親コンポーネントです</h3>
    <input type="text" v-model="メッセージ" />
    <p>子コンポーネントからメッセージを受信しました: {{ messageFromChild }}</p>
    <子:messageFromParent="メッセージ" @on-receive="受信" />
  </div>
</テンプレート>
<スクリプト>
'./child' から子をインポートします
エクスポートデフォルト{
  名前: '親'、
  データ() {
    戻る {
      message: '', // 子コンポーネントに渡されるメッセージ messageFromChild: '',
    }
  },
  コンポーネント:
    子供、
  },
  メソッド: {
    受信(msg) { // 子コンポーネントの情報を受け取り、messageFromChildに割り当てます
      this.messageFromChild = メッセージ
    },
  },
}
</スクリプト>

効果プレビュー

2. Vスロット

導入

v-slot は、スロットと名前付きスロットの統一された実装のために Vue2.6 で追加された新しい API であり、slot (2.6.0 で廃止)、slot-scope (2.6.0 で廃止)、scope (2.5.0 で廃止) などの API を置き換えるために使用されます。

v-slot は、名前付きスロットまたはプロパティを受け取る必要のあるスロットを提供するためにテンプレート タグで使用されます。v-slot が指定されていない場合は、デフォルト値が使用されます。

コードサンプル

以下の v-slot のコード例を参照してください。この例では次のことが実現されています。

親から子への値の受け渡し: 親コンポーネントは、<template v-slot:child>{{ message }}</template> を通じて親コンポーネントのメッセージ値を子コンポーネントに渡し、子コンポーネントは <slot name="child"></slot> を通じて対応するコンテンツを受け取ります。これにより、親から子への値の転送が実現されます。

// サブコンポーネントコード <テンプレート>
  <div class="child">
    <h4>これは子コンポーネントです</h4>
    <p>親コンポーネントからメッセージを受信しました:
      <slot name="child"></slot> <!--親コンポーネントからスロットを通じて渡された {{message}} を表示します-->
    </p>
  </div>
</テンプレート>
<テンプレート>
  <div class="parent">
    <h3>これは親コンポーネントです</h3>
    <input type="text" v-model="メッセージ" />
    <子供>
      <テンプレート v-slot:child>
        {{ message }} <!--スロットに表示されるコンテンツ-->
      </テンプレート>
    </子>
  </div>
</テンプレート>
<スクリプト>
'./child' から子をインポートします
エクスポートデフォルト{
  名前: '親'、
  データ() {
    戻る {
      メッセージ: ''、
    }
  },
  コンポーネント:
    子供、
  },
}
</スクリプト>

効果プレビュー

3. $refs/ $parent/ $children/$root

導入

また、$refs/$parent/$children/$root などを通じて Vue コンポーネントのインスタンスを取得し、インスタンスにバインドされたプロパティとメソッドを取得して、コンポーネント間の通信を実現することもできます。

$refs: 通常、DOM 要素の属性を取得するには、$refs を DOM 要素にバインドします。コンポーネント通信を実装する際に、子コンポーネントに $refs をバインドして子コンポーネントのインスタンスを取得することもできます。

$parent: Vue で this.$parent を直接使用して、現在のコンポーネントの親コンポーネント インスタンス (存在する場合) を取得できます。

$children: 同様に、Vue で this.$children を直接使用して、現在のコンポーネントの子コンポーネント インスタンスの配列を取得することもできます。ただし、 this.$children 配列内の要素の添え字は、親コンポーネントによって参照される子コンポーネントの順序と必ずしも一致しないことに注意してください。たとえば、非同期に読み込まれた子コンポーネントは、 children 配列内の順序に影響を与える可能性があります。そのため、使用時には、サブコンポーネントの名前など、特定の条件に基づいて対応するサブコンポーネントを見つける必要があります。

$root: 現在のコンポーネントツリーのルート Vue インスタンスを取得します。現在のインスタンスに親がない場合、このインスタンスはそれ自身になります。 $root を通じて、コンポーネント間のレベル間通信を実現できます。

コードサンプル

$parent と $children の使用例を見てみましょう (これらの API の使用方法は似ているため、$refs と $root の使用についてはここでは詳しく説明しません)。この例では、次のように実装されています。

親から子への値の受け渡し: 子コンポーネントは、$parent.message を通じて親コンポーネント内のメッセージの値を取得します。

子から親への値の受け渡し: 親コンポーネントは $children を通じて子コンポーネント インスタンスの配列を取得し、配列をトラバースして、インスタンス名を通じて対応する Child1 子コンポーネント インスタンスを取得して child1 に割り当て、child1.message を通じて Child1 子コンポーネントのメッセージを取得します。

コードは次のとおりです。

// サブコンポーネント <テンプレート>
  <div class="child">
    <h4>これは子コンポーネントです</h4>
    <input type="text" v-model="メッセージ" />
    <p>親コンポーネントからメッセージを受信しました: {{ $parent.message }}</p> <!--親コンポーネントインスタンスのメッセージを表示します-->
  </div>
</テンプレート>
<スクリプト>
エクスポートデフォルト{
  名前: 'Child1'、
  データ() {
    戻る {
      message: '', // 親コンポーネントは this.$children を通じて子コンポーネントインスタンスのメッセージを取得できます
    }
  },
}
</スクリプト>
// 親コンポーネント <テンプレート>
  <div class="parent">
    <h3>これは親コンポーネントです</h3>
    <input type="text" v-model="メッセージ" />
    <p>子コンポーネントからメッセージを受信しました: {{ child1.message }}</p> <!--子コンポーネント インスタンスのメッセージを表示します-->
    <子供 />
  </div>
</テンプレート>
<スクリプト>
'./child' から子をインポートします
エクスポートデフォルト{
  名前: '親'、
  データ() {
    戻る {
      メッセージ: ''、
      子1: {},
    }
  },
  コンポーネント:
    子供、
  },
  マウント() {
    this.child1 = this.$children.find((child) => {
      return child.$options.name === 'Child1' // options.name を通じて対応する名前の子インスタンスを取得します})
  },
}
</スクリプト>

効果プレビュー

4. $attrs/$listener

導入

$attrs と $listeners はどちらも Vue2.4 で追加された新しい属性で、主にユーザーが高度なコンポーネントを開発するために使用されます。

$attrs: 親スコープでプロパティとして認識されず、v-bind="$attrs" を介して内部コンポーネントに渡すことができる属性プロパティを受け取るために使用します。高レベルのコンポーネントを作成するときに非常に便利です。

コンポーネントを作成するときに、param1、param2、param3 などの数十のパラメーターを受け取る必要があると想像してください。props を使用する場合は、props: ['param1'、'param2'、'param3'、...] を通じてそれらの多くを宣言する必要があります。これらのプロパティの一部をより深いサブコンポーネントに渡す必要がある場合は、さらに面倒になります。

$attrs を使用する場合、宣言は必要ありません。$attrs.param1、$attrs.param2 などを通じて直接使用でき、深いサブコンポーネントに渡す例も上記に示されているため、非常に便利です。

$listeners: 親スコープ内の v-on イベント リスナーが含まれます。これは、v-on="$listeners" を介して内部コンポーネントに渡すことができます。これは、渡す方法が $attrs と非常に似ている、より高レベルのコンポーネントを作成するときに非常に便利です。

コードサンプル

この例では、A、B、C の 3 つのコンポーネントがあり、それらの関係は [A [B [C]]] です。ここで、A は B の親コンポーネントであり、B は C の親コンポーネントです。つまり、レベル 1 コンポーネント A、レベル 2 コンポーネント B、レベル 3 コンポーネント C です。私たちは次のことを達成しました:

親から子への値の受け渡し: レベル 1 コンポーネント A は、:messageFromA="message" を通じてメッセージ属性をレベル 2 コンポーネント B に渡し、レベル 2 コンポーネント B は $attrs.messageFromA を通じてレベル 1 コンポーネント A のメッセージを取得します。

:messageFromA="メッセージ"
v-bind="$attrs"
$attrs.messageFromA

子から親に値を渡す: レベル 1 コンポーネント A は、@keyup="receive" を通じて子孫コンポーネントに keyup イベント リスナーをバインドし、レベル 2 コンポーネント B は、v-on="$listeners" を通じて keyup イベントをその入力タグにバインドします。レベル 2 コンポーネント B の入力ボックスに入力が行われると、レベル 1 コンポーネント A の受信コールバックがトリガーされ、レベル 2 コンポーネント B の入力ボックスの値がレベル 1 コンポーネント A の messageFromComp に割り当てられ、子から親に値が転送されます。

@keyup="受信"
<CompC v-on="$listeners" />
v-on="$リスナー"

コードは次のとおりです。

// レベル 3 コンポーネント C
<テンプレート>
  <div class="compc">
    <h5>これは C コンポーネントです</h5>
    <input name="compC" type="text" v-model="message" v-on="$listeners" /> <!--コンポーネント A のキーアップ リスナー コールバックを入力にバインドします -->
    <p>コンポーネント A からメッセージを受信しました: {{ $attrs.messageFromA }}</p>
  </div>
</テンプレート>
<スクリプト>
エクスポートデフォルト{
  名前: 'Compc',
  データ() {
    戻る {
      メッセージ: ''、
    }
  },
}
</スクリプト>
// レベル 2 コンポーネント B
<テンプレート>
  <div class="compb">
    <h4>これはBコンポーネントです</h4>
    <input name="compB" type="text" v-model="message" v-on="$listeners" /> <!--コンポーネント A のキーアップ リスナー コールバックを入力にバインドします -->
    <p>コンポーネント A からメッセージを受信しました: {{ $attrs.messageFromA }}</p>
    <CompC v-bind="$attrs" v-on="$listeners" /> <!--コンポーネント A の keyup のリスナー コールバックをコンポーネント C に渡し、コンポーネント A から渡された attrs をコンポーネント C に渡します -->
  </div>
</テンプレート>
<スクリプト>
'./compC' から CompC をインポートします。
エクスポートデフォルト{
  名前: 'CompB'、
  コンポーネント:
    コンプC、
  },
  データ() {
    戻る {
      メッセージ: ''、
    }
  },
}
</スクリプト>
// コンポーネント <template>
  <div class="compa">
    <h3>これはコンポーネントです</h3>
    <input type="text" v-model="メッセージ" />
    <p>{{ comp }} からメッセージを受信しました: {{ messageFromComp }}}</p>
    <CompB :messageFromA="message" @keyup="receive" /> <!-- 子孫コンポーネントの keyup イベントをリッスンし、子孫コンポーネントにメッセージを渡します -->
  </div>
</テンプレート>
<スクリプト>
'./compB' から CompB をインポートします。
エクスポートデフォルト{
  名前: 'CompA'、
  データ() {
    戻る {
      メッセージ: ''、
      メッセージ送信元: '',
      構成: ''、
    }
  },
  コンポーネント:
    コンプB、
  },
  メソッド: {
    受信(e) { // 子孫コンポーネントのキーアップイベントのコールバックをリッスンし、キーアップが配置されている入力ボックスの値をmessageFromCompに割り当てます。
      this.comp = e.target.name
      this.messageFromComp = e.target.value
    },
  },
}
</スクリプト>

効果プレビュー

5. 提供する/注入する

導入

provide/inject のオプションのペアは、コンポーネント階層の深さに関係なく、上流と下流の関係が維持されている限り常に有効である、祖先コンポーネントがすべての子孫に依存関係を注入できるようにするため、一緒に使用する必要があります。 React に精通している場合は、非常によく似た Context API をすぐに思い浮かべるでしょう。

provide: はオブジェクト、またはオブジェクトを返す関数です。このオブジェクトには、子孫に注入できるプロパティ、つまり子孫に渡される属性と属性値が含まれています。

injcet: 文字列の配列、またはオブジェクト。文字列配列の場合、受け取った属性がデータから provide 内の属性に変更されることを除いて、使用方法は props と非常に似ています。オブジェクトの場合、props と同様に、default や from などのプロパティを設定することでデフォルト値を設定したり、サブコンポーネントで新しい名前付きプロパティを使用したりすることができます。

コードサンプル

この例には、レベル 1 コンポーネント A、レベル 2 コンポーネント B、レベル 3 コンポーネント C の 3 つのコンポーネントがあります: [A [B [C]]]。ここで、A は B の親コンポーネントであり、B は C の親コンポーネントです。この例では以下を実装します。

親から子への値の受け渡し: レベル 1 コンポーネント A は provide を通じて子孫コンポーネントにメッセージを挿入し、レベル 2 コンポーネント B は inject: ['messageFromA'] を通じてレベル 1 コンポーネント A のメッセージを受信し、messageFromA.content を通じてレベル 1 コンポーネント A のメッセージのコンテンツ プロパティ値を取得します。

レベル間の下向きの値の伝送: レベル 1 コンポーネント A は、provide を通じて子孫コンポーネントにメッセージを挿入します。レベル 3 コンポーネント C は、inject: ['messageFromA'] を通じてレベル 1 コンポーネント A のメッセージを受信し、messageFromA.content を通じてレベル 1 コンポーネント A のメッセージのコンテンツ プロパティ値を取得して、レベル間の下向きの値の伝送を実現します。

コードは次のとおりです。

// レベル 1 コンポーネント A
<テンプレート>
  <div class="compa">
    <h3>これはコンポーネントです</h3>
    <input type="text" v-model="message.content" />
    <コンプB />
  </div>
</テンプレート>
<スクリプト>
'./compB' から CompB をインポートします。
エクスポートデフォルト{
  名前: 'CompA'、
  提供する() {
    戻る {
      messageFromA: this.message, // provide を通じて子孫コンポーネントにメッセージを渡す}
  },
  データ() {
    戻る {
      メッセージ: {
        コンテンツ: ''、
      },
    }
  },
  コンポーネント:
    コンプB、
  },
}
</スクリプト>
// レベル 2 コンポーネント B
<テンプレート>
  <div class="compb">
    <h4>これはBコンポーネントです</h4>
    <p>コンポーネント A からメッセージを受信しました: {{ messageFromA && messageFromA.content }}</p>
    <コンプC />
  </div>
</テンプレート>
<スクリプト>
'./compC' から CompC をインポートします。
エクスポートデフォルト{
  名前: 'CompB'、
  inject: ['messageFromA'], // Aのprovideから渡されたメッセージをinject経由で受け入れる
  コンポーネント:
    コンプC、
  },
}
</スクリプト>
// レベル 3 コンポーネント C
<テンプレート>
  <div class="compc">
    <h5>これは C コンポーネントです</h5>
    <p>コンポーネント A からメッセージを受信しました: {{ messageFromA && messageFromA.content }}</p>
  </div>
</テンプレート>
<スクリプト>
エクスポートデフォルト{
  名前: 'Compc',
  inject: ['messageFromA'], // Aのprovideから渡されたメッセージをinject経由で受け入れる
}
</スクリプト>

注記:

学生の中には、上記の第 1 レベル コンポーネント A のメッセージで、vue の provide バインディングと inject バインディングがレスポンシブではないため、なぜ文字列型ではなくオブジェクト型が使用されているのかと質問する人もいるかもしれません。メッセージが文字列型の場合、第 1 レベル コンポーネント A の入力ボックスでメッセージ値を変更した後、messageFromA に割り当てることはできません。オブジェクト型の場合、オブジェクト属性値が変更されても、messageFromA の属性値はそれに応じて変更され、子孫コンポーネント インジェクトによって受信されるオブジェクト属性値もそれに応じて変更されます。

子孫が祖先と同じ属性を提供する場合、子孫は祖先の提供値を上書きします。たとえば、レベル 2 コンポーネント B も provide を通じてレベル 3 コンポーネント C に messageFromA 値を挿入する場合、レベル 3 コンポーネント C の messageFromA は、レベル 1 コンポーネント A ではなく、レベル 2 コンポーネント B によって挿入された値を優先的に受信します。

効果プレビュー

6. イベントバス

導入

EventBus (イベント バスとも呼ばれます) は、新しい Vue インスタンスを登録し、このインスタンスの $emit と $on を呼び出してこのインスタンスのイベントをリッスンおよびトリガーし、パラメーターを渡すことでコンポーネントのグローバル通信を実現します。 DOMを持たないコンポーネントであり、インスタンスメソッドのみを持つため、非常に軽量です。

これをグローバル Vue インスタンスに登録することで実行できます。

// メイン.js
Vue.prototype.$Bus = 新しいVue()

しかし、プロジェクトが大きすぎる場合は、イベント バスを 1 つのファイルに抽象化し、使用する必要がある各コンポーネント ファイルにインポートする方がよいでしょう。こうすることで、グローバル名前空間が汚染されることはありません。

// bus.js を import import Vue from 'vue' でインポートします
エクスポートconstBus = new Vue()

原理分析

eventBus の原理は実は非常に単純で、サブスクリプション パブリッシング モードを使用し、$emit と $on の 2 つのメソッドを実装することです。

// eventBus 原則エクスポート デフォルトクラス Bus {
  コンストラクタ() {
    this.callbacks = {}
  }
  $on(イベント, fn) {
    this.callbacks[イベント] = this.callbacks[イベント] || []
    this.callbacks[イベント].push(fn)
  }
  $emit(イベント、引数) {
    this.callbacks[イベント].forEach((fn) => {
      fn(引数)
    })
  }
}

// main.js に以下をインポートします // Vue.prototype.$bus = new Bus()

コードサンプル

この例では、合計 4 つのコンポーネントがあります: [A [B [C, D]]]、レベル 1 コンポーネント A、レベル 2 コンポーネント B、レベル 3 コンポーネント C、レベル 3 コンポーネント D。これはeventBusを使用して実現しました。

グローバル通信: これには、親コンポーネントと子コンポーネント間の通信、兄弟コンポーネント間の通信、およびレベル間コンポーネント間の通信が含まれます。 4 つのコンポーネントの動作ロジックは同じです。入力ボックスに入力すると、this.$bus.$emit('sendMessage', obj) を通じて sendMessage イベント コールバックがトリガーされ、送信者とメッセージがオブジェクトにカプセル化されてパラメーターとして渡されます。同時に、this.$bus.$on('sendMessage', obj) を通じて他のコンポーネントの sendMessage イベントがリッスンされ、現在のコンポーネントの送信者とメッセージの値がインスタンス化されます。このようにして、いずれかのコンポーネント入力ボックスの値が変更されると、他のコンポーネントが対応する情報を受信し、グローバル通信を実現できます。

コードは次のとおりです。

// メイン.js
Vue.prototype.$bus = 新しいVue()
// レベル 1 コンポーネント A
<テンプレート>  
  <div class="コンテナA">   
    <h2>CompA です</h2>  
    <input type="text" v-model="message" @keyup="sendMessage" />   
    <p v-show="messageFromBus && 送信者 !== $options.name">      
      {{ sender }} からメッセージを受信しました: {{ messageFromBus }}   
    </p>   
    <コンプB /> 
  </div>
</テンプレート>
<スクリプト>
'./compB' から CompB をインポートします。
エクスポートデフォルト{  
  名前: 'CompA'、 
  コンポーネント:   
    コンプB、  
  },  
  データ() {  
    戻る {    
      メッセージ: ''、    
      messageFromBus: ''、      
      送信者: ''、   
    } 
  },  
  マウント() {   
    this.$bus.$on('sendMessage', (obj) => { // eventBus を通じて sendMessage イベントをリッスンします const { sender, message } = obj    
      this.sender = 送信者     
      this.messageFromBus = メッセージ  
    }) 
  }, 
  メソッド: {  
    メッセージを送信する(){     
      this.$bus.$emit('sendMessage', { // eventBus sender を通じて sendMessage イベントをトリガーします: this.$options.name,     
        メッセージ: this.message、   
      })   
    }, 
  },
}
</スクリプト>
// レベル 2 コンポーネント B
<テンプレート> 
  <div class="コンテナB">   
    <h3>これは CompB です</h3>  
    <input type="text" v-model="message" @keyup="sendMessage" />  
    <p v-show="messageFromBus && 送信者 !== $options.name">     
      {{ sender }} からメッセージを受信しました: {{ messageFromBus }}  
    </p>  
    <コンプC />  
    <コンプD /> 
  </div>
</テンプレート>
<スクリプト>
'./compC' から CompC をインポートします。
'./compD' から CompD をインポートします。
エクスポートデフォルト{ 
  名前: 'CompB'、 
  コンポーネント:  
    コンプC、  
    コンプD、  
  }, 
  データ() {  
    戻る {    
      メッセージ: ''、   
      messageFromBus: ''、    
      送信者: ''、   
    } 
  }, 
  マウント() {    
    this.$bus.$on('sendMessage', (obj) => { // eventBus を通じて sendMessage イベントをリッスンします const { sender, message } = obj     
      this.sender = 送信者     
      this.messageFromBus = メッセージ  
    }) 
  }, 
  メソッド: {  
    メッセージを送信する(){   
      this.$bus.$emit('sendMessage', { // eventBus sender を通じて sendMessage イベントをトリガーします: this.$options.name,    
        メッセージ: this.message、    
     })   
   },  
 },
}
</スクリプト>
// レベル 3 コンポーネント C
<テンプレート> 
  <div class="コンテナC">  
    <p>これはCompCです</p>   
    <input type="text" v-model="message" @keyup="sendMessage" />   
    <p v-show="messageFromBus && 送信者 !== $options.name">      
      {{ sender }} からメッセージを受信しました: {{ messageFromBus }}  
    </p> 
  </div>
</テンプレート>
<スクリプト>
エクスポートデフォルト{  
  名前: 'CompC',
  データ() {   
    戻る {   
      メッセージ: ''、   
      messageFromBus: ''、   
      送信者: ''、   
    } 
  }, 
  マウント() {  
    this.$bus.$on('sendMessage', (obj) => { // eventBus を通じて sendMessage イベントをリッスンします const { sender, message } = obj    
      this.sender = 送信者    
      this.messageFromBus = メッセージ   
    })  
  },
  メソッド: {   
    メッセージを送信する(){    
      this.$bus.$emit('sendMessage', { // eventBus sender を通じて sendMessage イベントをトリガーします: this.$options.name,     
        メッセージ: this.message、     
      })   
    }, 
  },
}
</スクリプト>
// レベル 3 コンポーネント D
<テンプレート> 
  <div class="containerD">   
    <p>これは CompD です</p>   
    <input type="text" v-model="message" @keyup="sendMessage" />   
    <p v-show="messageFromBus && 送信者 !== $options.name">     
      {{ sender }} からメッセージを受信しました: {{ messageFromBus }} 
    </p> 
  </div>
</テンプレート>
<スクリプト>
エクスポートデフォルト{ 
  名前: 'CompD', 
  データ() {  
    戻る {   
      メッセージ: ''、   
      messageFromBus: ''、   
      送信者: ''、   
    } 
  }, 
  マウント() {   
    this.$bus.$on('sendMessage', (obj) => { // eventBus を通じて sendMessage イベントをリッスンします const { sender, message } = obj    
      this.sender = 送信者   
      this.messageFromBus = メッセージ   
    }) 
  }, 
  メソッド: {  
    メッセージを送信する(){   
      this.$bus.$emit('sendMessage', { // eventBus sender を通じて sendMessage イベントをトリガーします: this.$options.name,     
        メッセージ: this.message、   
      })  
    }, 
  },
}
</スクリプト>

効果プレビュー

画像が大きすぎるので、スクリーンショットを撮ってください

7. ヴュークス

プロジェクトが大きくなり、複数の人が同じプロジェクトを保守する場合、グローバル通信にイベント バスを使用すると、グローバル変数の変化を予測することが困難になる可能性があります。こうして、Vuex が誕生しました。

Vuex は、Vue.js アプリケーション専用に開発された状態管理パターンです。集中型ストレージを使用してアプリケーションのすべてのコンポーネントのステータスを管理し、対応するルールを使用して、ステータスが予測可能な方法で変更されるようにします。

Vuexの詳細については、公式のVuexドキュメント[1]を参照してください。ここでは詳しく説明しませんので、コードを見てみましょう。

コードサンプル

Vuex インスタンスとイベント バス レベルには、[A [B [C, D]]]、レベル 1 コンポーネント A、レベル 2 コンポーネント B、レベル 3 コンポーネント C、レベル 3 コンポーネント D の 4 つのコンポーネントも含まれています。この例では以下を実装しました。

グローバル通信: コードの内容はeventBusと似ていますが、eventBusよりもはるかに簡単に使用できます。各コンポーネントは、watch を通じて入力ボックスの変更を監視し、vuex の commit を通じて変更をトリガーして stroe の値を変更します。次に、各コンポーネントは計算を通じてストアからデータを動的に取得し、それによってグローバル通信を実現します。

//ストア.js
'vue' から Vue をインポートします
'vuex' から Vuex をインポートします
Vue.use(Vuex)
デフォルトの新しいVuex.Storeをエクスポートします({
  州: {
    メッセージ: {
      送信者: ''、
      コンテンツ: ''、
    },
  },
  突然変異:
    送信メッセージ(状態、オブジェクト) {
      状態.メッセージ = {
        送信者: obj.sender、
        コンテンツ: obj.content,
      }
    },
  },
})
// コンポーネントA
<テンプレート>
  <div class="コンテナA">
    <h2>CompA です</h2>
    <input type="text" v-model="メッセージ" />
    <p v-show="messageFromStore && 送信者 !== $options.name">
      {{ sender }} からメッセージを受信しました: {{ messageFromStore }}
    </p>
    <コンプB />
  </div>
</テンプレート>
<スクリプト>
'./compB' から CompB をインポートします。
エクスポートデフォルト{
  名前: 'CompA'、
  コンポーネント:
    コンプB、
  },
  データ() {
    戻る {
      メッセージ: ''、
    }
  },
  計算: {
    メッセージFromStore() {
      this.$store.state.message.content を返します
    },
    送信者() {
      this.$store.state.message.sender を返します
    },
  },
  時計:
    メッセージ(新しい値) {
      this.$store.commit('sendMessage', {
        送信者: this.$options.name,
        コンテンツ: newValue、
      })
    },
  },
}
</スクリプト>

eventBus と同様に、コンポーネント B、C、D のコードはサブコンポーネントの導入の違いを除いて同じなので、詳細は説明しません。

効果プレビュー

要約する

上記では合計 7 つの Vue コンポーネント通信方法について説明しました。実行できる通信の種類は次の図に示されています。

  • props/$emit: 親コンポーネントと子コンポーネント間の双方向通信を実現できます。これは通常、日常的な親子コンポーネント通信で最もよく使用される選択肢です。
  • v-slot: 親コンポーネントと子コンポーネント間の一方向通信(親が子に値を渡す)を実現できます。再利用可能なコンポーネントを実装する場合、DOM ノード、html などのコンテンツをコンポーネントに渡す場合、および一部のコンポーネント ライブラリでテーブル値の 2 次処理を行う場合は、v-slot を優先できます。
  • $ refs/$ parent/ $ children/ $ root: 親コンポーネントと子コンポーネント間の双方向通信を実現できます。その中で、$root は、レベルを超えてルート コンポーネント インスタンスから子コンポーネントへの一方向の値転送を実現できます。 親コンポーネントが v-on バインディングを介して値を渡したりリッスンしたりしない場合、親コンポーネントと子コンポーネントは互いのプロパティまたはメソッドを取得するときにこれらの API の使用を検討できます。
  • $attrs/$listeners: レベル間の双方向通信を可能にし、受信属性とバインドされたリスナーを簡単に取得し、それらを下位レベルのサブコンポーネントに簡単に渡すことができるため、高度なコンポーネントを構築するときに非常に便利です。
  • 提供/注入: レベル間の一方向通信を実現し、子孫コンポーネントに依存関係を軽く注入できます。これは、高度なコンポーネントを実装し、コンポーネント ライブラリを作成する場合の最適な選択肢です。
  • eventBus: グローバル通信を実現できます。プロジェクト規模が大きくない場合は、eventBus を使用してグローバル イベント監視を実現できます。ただし、グローバルな汚染やメモリ リークを回避するために、eventBus は注意して使用する必要があります。
  • Vuex: グローバル通信を実現でき、Vue プロジェクトのグローバル状態管理のベストプラクティスです。プロジェクトが大きく、グローバルコンポーネントのステータスを集中管理したい場合は、Vuex をインストールするのが正しい選択です。

以上が、Vue コンポーネントの 7 つの通信方法についての詳細な内容です。Vue コンポーネントの通信方法についての詳細は、123WORDPRESS.COM の他の関連記事にも注目してください。

以下もご興味があるかもしれません:
  • Vueの親子コンポーネントの通信方法は次のとおりです
  • Vue の非親子コンポーネント間の通信を理解していますか?
  • Vue3の7つのコンポーネント通信方式の詳細説明
  • Vueコンポーネント間の4つの通信方法の詳細な説明
  • Vueコンポーネント間の通信についてどれくらい知っていますか

<<:  MySQLにおける時刻日付型と文字列型の選択について

>>:  CnBlogs カスタムブログスタイルの共有

推薦する

JavaScript にはすでに Object があるのに、なぜ Map が必要なのでしょうか?

目次1. オブジェクトをマップとして扱わない1. 未定義のプロパティはプロトタイプチェーンを通じてア...

...

MySQL テーブルを作成するためによく使用される SQL ステートメントの概要

最近、私はプロジェクトに取り組んでおり、背景を記述するために SQL ステートメントを使用する必要が...

Docker View プロセス、メモリ、カップ消費量

Docker プロセス、メモリ、カップ消費量を表示dockerコンテナを起動し、dockerinsp...

ウェブページを最適化してメモリとCPUの使用率を削減

一部の Web ページは大きく見えなくても開くのに非常に時間がかかる場合があります。一方、他の We...

vue3で注意すべき2つのポイントを詳しく解説:セットアップ

目次vue2の場合vue3ではセットアップに関する注意事項セットアップライフサイクルは、before...

Centos7.3は起動時に自動的に起動または指定されたコマンドを実行します

Centos7では、/etc/rc.d/rc.localファイルの権限が削減されており、実行権限があ...

MySQL データを誤って削除した場合の簡単な解決策 (MySQL フラッシュバック ツール)

概要Binlog2sql は、Python で開発されたオープンソースの MySQL Binlog ...

MySQL のストレージ エンジンの違いと比較

MyISAM ストレージエンジンMyISAM は ISAM ストレージ エンジンに基づいており、それ...

JavaScript の Strict モードの詳細な説明

目次導入厳密モードの使用厳格モードの新機能例外を強制的にスローする変数の使用を簡素化する議論を単純化...

CSS変数を使用してダークモードを実装するためのサンプルコード

最近、WeChatはAppleによってダークモードの開発を強制されました。ますます多くのウェブサイト...

JSはシンプルなカウンターを実装します

HTML CSS および JavaScript を使用して、プラス、マイナス、ゼロの 3 つのボタン...

XAML でボタンを円として再描画する方法

XAML レイアウトを使用する場合、インターフェイスを Metro 風にするために、一部のボタンでは...

JavaScript データ型変換の例 (他の型を文字列、数値型、ブール型に変換する)

序文データ型変換とは何ですか?フォームまたはプロンプトを使用して取得されるデフォルトのデータ型は文字...

年末ですが、MySQL パスワードは安全ですか?

序文:年末です。データベースを検査する時期ではないでしょうか?一般的に、検査では、パスワードの複雑さ...