Vue での親子コンポーネント通信と、sync を使用して親子コンポーネント データを同期する

Vue での親子コンポーネント通信と、sync を使用して親子コンポーネント データを同期する

序文

親子コンポーネントの通信は、次の 2 つのケースに分けられます。

1. 親コンポーネントが子コンポーネントにデータを渡す
2. 子コンポーネントが親コンポーネントにデータを渡す

一般的に言えば、状況 1 のデータ転送の問題は props によって解決できるため、ここでは詳細には触れません。

子コンポーネントは親コンポーネントにデータを渡す

主に2つのシナリオの実現について話しますが、方法は3つあります。

1. 親コンポーネントは、props を通じて、データとデータを変更する関数を子コンポーネントに渡します。子コンポーネントで親コンポーネントから渡された関数を呼び出すことで、親コンポーネントのデータが更新されます (親コンポーネントにデータが渡されます) (子コンポーネントでは対応する応答イベントが必要です)

2. 子コンポーネントでカスタムイベント(vm.$emit)をトリガーすると、v-on: [カスタムイベント]を使用してデータが親コンポーネントに返され、関数をリッスンします。

3. ref を通じて子コンポーネントをマークすると、親コンポーネントは vm.$refs.[子コンポーネント ref].[子コンポーネントのプロパティ/メソッド] を通じて子コンポーネントのデータを直接取得できます。

以下に一つずつ紹介します

1. 親コンポーネントから子コンポーネントにpropsを介して関数を渡し、親コンポーネントのデータを変更する関数を呼び出す

ここにはコードは表示されません

まず、これは比較的単純であり、次に、これは明らかに Vue のベストプラクティスではありません (React ではより一般的です)。
コードを確認したい場合は、こちらをご覧ください: 「【Vue】Vue のさまざまなシナリオにおけるコンポーネント間のデータ交換に関する簡単な説明」 http://www.cnblogs.com/penghuwan/p/7286912.html (兄弟コンポーネント間のデータ交換のセクション)

2. カスタムイベントを通じて子コンポーネントから親コンポーネントにデータを渡す

$emit(event, [...parameters]) を通じて子コンポーネントでカスタムイベントをトリガーできるため、親コンポーネントは v-on を直接使用して、子コンポーネントが使用されている場所で子コンポーネントによってトリガーされたイベントをリッスンし、リスニング関数で子コンポーネントから渡されたすべてのパラメータを順番に取得できます。

例えば:
サブコンポーネントに記述します:

this.emit('eventYouDefined', arg);

次に、親コンポーネントの子コンポーネント テンプレートでリッスンできます。
// 親コンポーネントのテンプレートは次のとおりです:

<Son v-on: eventYouDefined = "functionYours" />

ここに例があります

親コンポーネント

<テンプレート>
  <div id="父">
    <div>
       私は親コンポーネントであり、以下を受け取りました:
      {{ text || 'まだデータがありません' }}
      <son v-on:sendData='getSonText'></son>
    </div>
  </div>
</テンプレート>
 
<スクリプト>
'./son.vue' から son をインポートします。
エクスポートデフォルト{
  データ: 関数 () {
    戻る {
      文章: ''
    }
  },
  コンポーネント:
    息子:息子
  },
  メソッド: {
    getSonText (テキスト) {
      this.text = テキスト
    }
  }
}

</スクリプト>
 
<スタイルスコープ>
#父 div {
  パディング: 10px;
  マージン: 10px;
  境界線: 1px のグレー実線;
  オーバーフロー: 非表示;
}
</スタイル>

サブコンポーネント:

<テンプレート>
  <div>
    <p>私は子コンポーネントです。私が持っているデータは次のとおりです: {{ text }}</p>
    <ボタン @click="sendData">
      データを送信</button>
  </div>
</テンプレート>
 
<スクリプト>
エクスポートデフォルト{
  データ () {
    戻る {
      テキスト: '子コンポーネントからのデータ'
    }
  },
  メソッド: {
    送信データ() {
      this.$emit('sendData', this.text)
    }
  }
}
</スクリプト>
 
<!-- CSS をこのコンポーネントのみに制限するために "scoped" 属性を追加します -->
<スタイルスコープ>
   ボタン { float: 左 }
</スタイル>

子コンポーネントの「データの送信」ボタンをクリックする前に、親コンポーネントがデータを受信して​​いない(テキストが空の文字列)場合、{{ text || 'データはまだありません' }} はデフォルトのテキスト「データはまだありません」を表示します。

「データを送信」ボタンをクリックした後:

sendDataカスタムイベントがトリガーされるため、

this.$emit('sendData', this.text) //ここでは子コンポーネントのインスタンスを指します)

子コンポーネントのテキスト データは親コンポーネントにあります。

 <son v-on:sendData='getSonText'></son>

コンポーネント内の getSonText 関数はパラメータをパラメータとして受け取り、子コンポーネントから親コンポーネントへのパラメータ転送プロセスを完了します。

3. ref属性を介して親コンポーネント内で子コンポーネントのデータを直接取得する

上で説明した処理シナリオ 1 と 2 には、両方ともイベント メカニズム (クリックなどのネイティブ イベントかカスタム イベントか) に基づく必要があり、関数はイベントが発生したときにのみ呼び出されてデータを渡すことができるという制限があります。

しかし、子コンポーネントに「ボタン」のようなものが存在せず、ネイティブ イベントを作成できず、カスタム イベントをトリガーするタイミングを見つける方法がない場合は、どのようにして子コンポーネントから親コンポーネントにデータを渡すことができるのでしょうか。 ?

現時点では、ref属性を使用して親コンポーネントから子コンポーネントのデータを「直接取得」することしかできません。

Ref はよく使用する Vue 属性です。これを使用すると、このコンポーネントのテンプレートから DOM インスタンスを簡単に便利に取得できます。実際、親コンポーネントで子コンポーネントの ref を設定すると、vm.$refs.[子コンポーネントの ref].[子コンポーネントの属性] を通じてデータを直接取得できます。例:

親コンポーネント:

<テンプレート>
  <div id="父">
    <div>
       私は親コンポーネントであり、以下を受け取りました:
      {{ text || 'まだデータがありません' }}
      <button @click="getSonText()">データを受け入れる</button>
      <息子ref='息子'></息子>
    </div>
  </div>
</テンプレート>
 
<スクリプト>
'./son.vue' から son をインポートします。
エクスポートデフォルト{
  データ: 関数 () {
    戻る {
      文章: ''
    }
  },
  コンポーネント:
    息子:息子
  },
  メソッド: {
    テキストを取得する() {
      this.text = this.$refs.son.text
    }
  }
}

</スクリプト>
 
<スタイルスコープ>
#父 div {
  パディング: 10px;
  マージン: 10px;
  境界線: 1px の灰色
  オーバーフロー: 非表示;
}
</スタイル>

サブコンポーネント:

<テンプレート>
  <div>
    <p>私は子コンポーネントです。私が持っているデータ: {{ text }}</p>
  </div>
</テンプレート>
 
<スクリプト>
エクスポートデフォルト{
  データ () {
    戻る {
      テキスト: '子コンポーネントからのデータ'
    }
  }
}
</スクリプト>
 
<!-- CSS をこのコンポーネントのみに制限するために "scoped" 属性を追加します -->
<スタイルスコープ>
   ボタン { float: 左 }
</スタイル>

デモ:

「データを受け入れる」ボタンをクリックする前に:

「データを受け入れる」ボタンをクリックした後:

同期を使用して双方向のデータバインディングを実現し、親子コンポーネントのデータを同期します。

上記の 3 つの方法により、親子コンポーネントの通信シナリオのほとんどを解決できると思いますが、上記の通信シナリオを注意深く考えてみると、まだ問題があることがわかります。

子コンポーネントから親コンポーネントにデータを渡す場合、親コンポーネントと子コンポーネントのデータは常に同期されるわけではありません。

しかし、特別な要求のシナリオでは、親コンポーネントと子コンポーネントのデータを常に同期させたい場合があります。この場合、次のようにします。

これは親コンポーネントのテンプレートです:

<son :foo="bar" v-on:update="val => bar = val"></son>

子コンポーネントでは、props宣言を通じてfooを受け取り、

小道具: {
     foo: [タイプ]
}

同時に、サブコンポーネント内のデータが変更されるたびに、

this.$emit('update', newValue)

親コンポーネント テンプレートのリスニング関数の「val」にパラメーター newValue を渡します。そしてパス

val => バー = val

この式は、bar = newValue を実装します。この時点で、親コンポーネントのキー データ bar が子コンポーネントによって変更 (等しい) されていることがわかります。

双方向データバインディングにより、親(コンポーネント)は子のデータを変更でき、子も親のデータを変更できる。

Vue は上記のコードを簡略化するために sync 修飾子を提供します。次に例を示します。

<comp :foo.sync="bar"></comp>

次のように拡張されます:

<comp :foo="bar" @update:foo="val => bar = val"></comp>

次に、子コンポーネント内の親コンポーネントのデータを変更する必要がある場合は、次のカスタム イベントをトリガーする必要があります。

this.$emit("update:foo", newValue)

[注意] これは、前述の「カスタム イベント (emit) を介して子コンポーネントから親コンポーネントにデータを渡す」セクションの内容と重複しているように感じられるかもしれません。

しかし、そうではありません。両者の親子コンポーネント関係には違いがあります。以下では、重要なコード行を使用してその違いを証明します。

1. 同期について説明するセクションでは、カスタム イベントが発生したときに実行される応答式は次のとおりです。
<son :foo="bar" v-on:update="val => bar = val"></son> 内の "val => bar = val"

2. 「カスタム イベントを通じて子コンポーネントから親コンポーネントにデータを渡す」の 2 番目の部分では、カスタム イベントが発生したときに実行される応答式は次のとおりです。
<Son v-on: eventYouDefined = "arg => functionYours(arg)" />

前者の場合、式 val => bar = val は、親コンポーネントのデータが子コンポーネントから渡されたデータと等しくなるように強制することを意味します。 このとき、親コンポーネントと子コンポーネントの状態が等しいことがわかります。 親は子(データ)を変更でき、子も親(データ)を変更できる

後者の場合、関数 Yours は親コンポーネントで定義されます。この関数では、子コンポーネントから受け取った arg データに対して任意の操作や処理を実行できます。決定権は完全に親コンポーネントにあります。つまり、親は子 (データ) を変更できますが、子は親 (データ) を直接変更することはできません。親のデータの変更は、それ自体によってのみ判断できる。

デモはこちらです:

親コンポーネント:

<テンプレート>
  <div id="父">
    <div>
       私は親コンポーネントです<息子
        :wisdom.sync="知恵"
        :magic.sync="マジック"
        :attack.sync="攻撃"
        :defense.sync="防御">
      </息子>
      <p>知性: {{ 知恵 }}</p>
      <p>膜法: {{ magic }}</p>
      <p>攻撃: {{ attack }}</p>
      <p>防御: {{defense }}}</p>
    </div>
  </div>
</テンプレート>
 
<スクリプト>
'./son.vue' から son をインポートします。
エクスポートデフォルト{
  データ: 関数 () {
    戻る {
      知恵: 90,
      魔法: 160,
      攻撃力: 100,
      防御力: 80
    }
  },
  コンポーネント:
    息子:息子
  }
}

</スクリプト>
 
<スタイルスコープ>
#父 div {
  パディング: 10px;
  マージン: 10px;
  境界線: 1px の灰色
  オーバーフロー: 非表示;
}
</スタイル>

サブコンポーネント:

<テンプレート>
  <div>
    <p>私はサブコンポーネントです</p>
    <p>知性: {{ 知恵 }}</p>
    <p>膜法: {{ magic }}</p>
    <p>攻撃: {{ attack }}</p>
    <p>防御: {{defense }}}</p>
    <button @click="increment('wisdom')">知性を高める</button>
    <button @click="increment('magic')">膜を増やす方法</button>
    <button @click="increment('attack')">攻撃力を上げる</button>
    <button @click="increment('defense')">防御力を上げる</button>
  </div>
</テンプレート>
 
<スクリプト>
エクスポートデフォルト{
  小道具: {
    知恵:数、
    魔法: 数字、
    攻撃: 数、
    防御: 番号
  },

  メソッド: {
    増分(データ名) {
      newValue = this[dataName] + 1 とします
      this.$emit(`update:${dataName}`, newValue)
    }
  }
}
</スクリプト>
 
<!-- CSS をこのコンポーネントのみに制限するために "scoped" 属性を追加します -->
<スタイルスコープ>
   ボタン { float: 左 }
</スタイル>

クリック前

サブコンポーネントの追加で「インテリジェンスの増加」ボタンをクリックすると、親コンポーネントとサブコンポーネントの両方のインテリジェンス パラメータが 90 から 91 に変更されます。

「サブコンポーネントの追加」で「膜メソッドの追加」ボタンをクリックすると、親コンポーネントとサブコンポーネントのインテリジェンス パラメータが同時に 160 から 161 に変更されます。

双方向データバインディングは諸刃の剣である

利点から:

1. 親子コンポーネントデータの「リアルタイム」同期を実現し、いくつかのデータシナリオで使用できます。
2. syncが提供する構文糖により、双方向バインディングのコードが非常にシンプルになります。

欠点としては:

これにより、一方向のデータフローのシンプルさが損なわれ、データの分析の難易度が高まります。

同期によって変更されたプロパティがオブジェクトの場合

上記の例を修正し、データをオブジェクトにラップして渡してみましょう。

親コンポーネント

<テンプレート>
  <div id="父">
    <div>
       私は親コンポーネントです <son :analysisData.sync="analysisData">
      </息子>
      <p>インテリジェンス: {{ analysisData.wisdom }}</p>
      <p>膜法: {{ analysisData.magic }}</p>
      <p>攻撃: {{ analysisData.attack }}</p>
      <p>防御: {{ analysisData.defense }}</p>
    </div>
  </div>
</テンプレート>
 
<スクリプト>
'./son.vue' から son をインポートします。
エクスポートデフォルト{
  データ: 関数 () {
    戻る {
      分析データ:
        知恵: 90,
        魔法: 160,
        攻撃力: 100,
        防御力: 80
      }
    }
  },
  コンポーネント:
    息子:息子
  }
}

</スクリプト>
 
<スタイルスコープ>
#父 div {
  パディング: 10px;
  マージン: 10px;
  境界線: 1px の灰色
  オーバーフロー: 非表示;
}
</スタイル>

サブコンポーネント

<テンプレート>
  <div>
    <p>私はサブコンポーネントです</p>
    <p>インテリジェンス: {{ analysisData.wisdom }}</p>
    <p>膜法: {{ analysisData.magic }}</p>
    <p>攻撃: {{ analysisData.attack }}</p>
    <p>防御: {{ analysisData.defense }}</p>
    <button @click="increment('wisdom')">知性を高める</button>
    <button @click="increment('magic')">膜を増やす方法</button>
    <button @click="increment('attack')">攻撃力を上げる</button>
    <button @click="increment('defense')">防御力を上げる</button>
  </div>
</テンプレート>
 
<スクリプト>
エクスポートデフォルト{
  小道具: {
    分析データ: オブジェクト
  },

  メソッド: {
    増分(データ名) {
      newObj = JSON.parse(JSON.stringify(this.analysisData)) とします。
      新しいオブジェクト[データ名] += 1
      this.$emit('update:analysisData', newObj)
    }
  }
}
</スクリプト>
 
<!-- CSS をこのコンポーネントのみに制限するために "scoped" 属性を追加します -->
<スタイルスコープ>
   ボタン { float: 左 }
</スタイル>

上記と同じデモ

子コンポーネントの参照型プロパティを変更することで、「親子コンポーネントのデータ同期」の要件を満たさないでください。

親コンポーネントのデータは子コンポーネントに渡されますが、これは通常、props を通じて実現されます。「親子コンポーネントのデータ同期」の要件を実装する場合、子コンポーネント内の参照型 (配列やオブジェクトなど) の props を変更することが実現可能であることがわかります。

1. 親コンポーネントのデータを同時に変更できるだけでなく(同じデータが元々参照されているため)
2. そして、Vue の検出メカニズムでは検出されません。 (エラーは報告されません)

しかし、これを行わないでください。データフローの分析が非常に難しくなります。これを試す場合は、上記のアプローチの方がおそらく優れています。これを行わないでください。悪いアプローチです。

親コンポーネント:

<テンプレート>
  <div id="父">
    <div>
       私は親コンポーネントです <son :analysisData="analysisData">
      </息子>
      <p>インテリジェンス: {{ analysisData.wisdom }}</p>
      <p>膜法: {{ analysisData.magic }}</p>
      <p>攻撃: {{ analysisData.attack }}</p>
      <p>防御: {{ analysisData.defense }}</p>
    </div>
  </div>
</テンプレート>
 
<スクリプト>
'./son.vue' から son をインポートします。
エクスポートデフォルト{
  データ: 関数 () {
    戻る {
      分析データ:
        知恵: 90,
        魔法: 160,
        攻撃力: 100,
        防御力: 80
      }
    }
  },
  コンポーネント:
    息子:息子
  }
}

</スクリプト>
 
<スタイルスコープ>
#父 div {
  パディング: 10px;
  マージン: 10px;
  境界線: 1px の灰色
  オーバーフロー: 非表示;
}
</スタイル>

サブコンポーネント:

<テンプレート>
  <div>
    <p>私はサブコンポーネントです</p>
    <p>インテリジェンス: {{ analysisData.wisdom }}</p>
    <p>膜法: {{ analysisData.magic }}</p>
    <p>攻撃: {{ analysisData.attack }}</p>
    <p>防御: {{ analysisData.defense }}</p>
    <button @click="increment ('wisdom')">知性を高める</button>
    <button @click="increment ('magic')">膜を増やす方法</button>
    <button @click="increment ('attack')">攻撃力を上げる</button>
    <button @click="increment ('defense')">防御力を上げる</button>
  </div>
</テンプレート>
 
<スクリプト>
エクスポートデフォルト{
  小道具: {
    分析データ: オブジェクト
  },

  メソッド: {
    増分(データ名) {
      obj = this.analysisData とします。
      obj[データ名] += 1
    }
  }
}
</スクリプト>
 
<!-- CSS をこのコンポーネントのみに制限するために "scoped" 属性を追加します -->
<スタイルスコープ>
   ボタン { float: 左 }
</スタイル>

以上が、Vue における親子コンポーネント通信の詳細と、sync を使用して親子コンポーネントのデータを同期する方法です。Vue の詳細については、123WORDPRESS.COM の他の関連記事にも注目してください。

以下もご興味があるかもしれません:
  • Vue2とVue3の兄弟コンポーネント通信バスの違いと使い方
  • Vue.js 親子コンポーネント通信開発例
  • Vue での親子コンポーネント通信における todolist コンポーネント機能の開発
  • Vue2 における 12 種類のコンポーネント通信
  • Vue3 の 10 個のコンポーネント通信方法の概要

<<:  Mysql データベース ストアド プロシージャの基本構文の説明

>>:  Linux でタイムアウト付きの接続関数を試す

推薦する

MySQLの再帰問題

MySQL自体は再帰構文をサポートしていませんが、自己接続を通じていくつかの単純な再帰を実現できます...

vue3 再帰コンポーネントカプセル化の全プロセス記録

目次序文1. 再帰コンポーネント2. 右クリックメニューコンポーネント要約する序文今日、プロジェクト...

CSS テキスト強調を使用してテキストを強調するための実装コード

1. はじめにこれまで、テキストの特定の部分を強調したい場合、通常は太字にしたり明るい色を使用したり...

一般的な CSS プロパティのブラウザ互換性の概要 (推奨)

CSS プロパティのブラウザ互換性をまとめる必要があるのはなぜですか?使用する際は、Can I U...

MySQL 5.7 解凍版のインストールとアンインストール、およびよくある問題の概要

1. インストール1. ダウンロードMySQLをダウンロードするには、MySQL公式サイトhttp:...

ウェブ開発で遭遇した問題と経験

<br />以下は開発中に遭遇した問題と、そこから得た経験です。デバッグに時間がかかりま...

HTMLのimgタグで画像の中心部分だけを表示する方法(3つの方法)

HTML の img タグで画像の中心を表示する方法は、現在 3 つあります。ここで記録しておきま...

Linux で MySQL データベースのスケジュールされたバックアップを実装する簡単な方法

詳細な手順は次のとおりです。 1. ディスク容量を確認します。 [root@localhost バッ...

JavaScript で H5 ゴールド コイン関数を実装する (サンプル コード)

今日は春節の金貨の赤い封筒のアクティビティを作りました。なかなか良い出来だと思います。皆さんと共有し...

Docker可視化ツールPortainerの導入と中国語翻訳

#docker 検索#docker プルポーター1. イメージを取得した後、中国語パッケージをダウン...

HTML5で見逃せないAPIやヒントのまとめ

これまでのブログ投稿では、HTML 5 ではあまり使われていないが注目すべき API やヒントに焦点...

Vue の基本入門: Vuex のインストールと使用

目次1. vuexとは何か2. インストールと導入3. vuexの使用4. プロセスの紹介5. 突然...

動的および静的分離を実現する nginx のサンプルコード

1. nginxの動的と静的の分離の簡単な設定web1は静的サーバー、web2は動的サーバー、nod...

Angularコンポーネントライフサイクルの詳細説明(I)

目次概要1. フックの呼び出し順序2. onChangesフック3. 変更検出メカニズムとDoChe...

WindowsシステムでMySQLデータベースを完全にアンインストールして、MySQLを再インストールします

1. コントロールパネルで、MySQLのすべてのコンポーネントをアンインストールします。コントロール...