web-dev-qa-db-ja.com

vuejsは子コンポーネントから親データを更新します

私はvuejs(2.0)で遊び始めています。 1つのコンポーネントを含む単純なページを作りました。ページにはデータを含む1つのVueインスタンスがあります。そのページで私はHTMLにコンポーネントを登録して追加しました。コンポーネントにはinput[type=text]が1つあります。その値を親(メインのVueインスタンス)に反映させたい。

コンポーネントの親データを正しく更新する方法親からバインドされたプロップを渡すことは良くありませんし、コンソールにいくつかの警告を投げます。彼らは彼らのドキュメントに何かを持っていますが、それはうまくいきません。

87
Gal Ziv

双方向バインディングは、イベント駆動型のアーキテクチャーを採用するため、Vue 2.0では推奨されなくなりました。一般的に、子供は小道具を変えてはいけません。そうではなく、 $emit イベントを発生させ、親にそれらのイベントに応答させるべきです。

あなたの特定のケースでは、あなたはv-modelでカスタムコンポーネントを使うことができます。これは双方向バインディングに近いものを可能にする特別な構文ですが、実際には上記のイベント駆動型アーキテクチャの省略形です。あなたはそれについてここで読むことができます - > https://vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events .

これは簡単な例です:

Vue.component('child', {
  template: '#child',
  
  //The child has a prop named 'value'. v-model will automatically bind to this prop
  props: ['value'],
  methods: {
    updateValue: function (value) {
      this.$emit('input', value);
    }
  }
});

new Vue({
  el: '#app',
  data: {
    parentValue: 'hello'
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>

<div id="app">
  <p>Parent value: {{parentValue}}</p>
  <child v-model="parentValue"></child>
</div>

<template id="child">
   <input type="text" v-bind:value="value" v-on:input="updateValue($event.target.value)">
</template>

ドキュメントはそれを述べています

<custom-input v-bind:value="something" v-on:input="something = arguments[0]"></custom-input>

と同等です

<custom-input v-model="something"></custom-input>

それが、子に対するプロップがvalueという名前である必要がある理由と、inputという名前のイベントを子が$発行する必要がある理由です。

123
asemahle

のドキュメントから

Vue.jsでは、親子コンポーネントの関係は、小道具が下がり、イベントが上がるようにまとめることができます。親は小道具を介して子にデータを渡し、子はイベントを介して親にメッセージを送信します。次にそれらがどのように機能するのかを見てみましょう。

enter image description here

小道具の渡し方

以下は子要素に小道具を渡すコードです。

<div>
  <input v-model="parentMsg">
  <br>
  <child v-bind:my-message="parentMsg"></child>
</div>

イベントの発行方法

HTML:

<div id="counter-event-example">
  <p>{{ total }}</p>
  <button-counter v-on:increment="incrementTotal"></button-counter>
  <button-counter v-on:increment="incrementTotal"></button-counter>
</div>

JS:

Vue.component('button-counter', {
  template: '<button v-on:click="increment">{{ counter }}</button>',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    increment: function () {
      this.counter += 1
      this.$emit('increment')
    }
  },
})
new Vue({
  el: '#counter-event-example',
  data: {
    total: 0
  },
  methods: {
    incrementTotal: function () {
      this.total += 1
    }
  }
})
92
Saurabh

子コンポーネント内:this.$emit('eventname', this.variable)

親コンポーネント内:

<component @eventname="updateparent"></component>

methods: {
    updateparent(variable) {
        this.parentvariable = variable
    }
}
21

子コンポーネント

親コンポーネントにイベントを送信するにはthis.$emit('event_name')を使用してください。

enter image description here

親コンポーネント

親コンポーネントでそのイベントをリッスンするために、v-on:event_nameを実行し、そのイベントで実行したいメソッド(ex. handleChange)が発生します

enter image description here

完了:)

上記のものに対するイベント発行およびvモデルの回答に同意します。ただし、これはgoogleから返された最初の記事の1つであると思われるため、親に送信したい複数のフォーム要素を持つコンポーネントについて見つけたものを投稿することにしました。

私は質問が単一の入力を指定していることを知っていますが、これは最も近いもののように見え、似たようなvueコンポーネントを持つ人々をいくらか時間を節約するかもしれません。また、.sync修飾子についてはまだ言及していません。

私の知る限りでは、v-modelソリューションは、親に戻る1つの入力にのみ適しています。私はそれを探すのに少し時間がかかりましたが、Vue(2.3.0)ドキュメントはコンポーネントに送られた複数の小道具を親に同期させる方法を示します(もちろんemitを介して)。

それは適切に.sync修飾子と呼ばれます。

これが ドキュメント の説明です。

場合によっては、プロップに対して「双方向バインディング」が必要になることがあります。残念ながら、真の双方向バインディングではメンテナンスの問題が発生する可能性があります。その変更の原因が親と子の両方で明らかであることなく、子コンポーネントが親を変更できるからです。

そのため、代わりにupdate:myPropNameのパターンでイベントを発行することをお勧めします。たとえば、titleプロップを持つ仮想のコンポーネントでは、新しい値を割り当てるという意図を次のように伝えます。

this.$emit('update:title', newTitle)

その後、親はそのイベントを監視し、必要に応じてローカルデータプロパティを更新できます。例えば:

<text-document   
 v-bind:title="doc.title"  
 v-on:update:title="doc.title = $event"
></text-document>

便宜上、.sync修飾子を使用してこのパターンの短縮形を示します。

<text-document v-bind:title.sync="doc.title"></text-document>

オブジェクトを介して送信することで、一度に複数を同期することもできます。ここで ドキュメントをチェックしてください

4
Archernar

ObjectまたはArrayとしてpropsを渡すことも可能です。この場合、データは双方向にバインドされます。

(これはトピックの最後に記載されています: https://vuejs.org/v2/guide/components.html#One-Way.co.jp-Flow

Vue.component('child', {
  template: '#child',
  props: {post: Object},
  methods: {
    updateValue: function () {
      this.$emit('changed');
    }
  }
});

new Vue({
  el: '#app',
  data: {
    post: {msg: 'hello'},
    changed: false
  },
  methods: {
    saveChanges() {
        this.changed = true;
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>

<div id="app">
  <p>Parent value: {{post.msg}}</p>
  <p v-if="changed == true">Parent msg: Data been changed - received signal from child!</p>
  <child :post="post" v-on:changed="saveChanges"></child>
</div>

<template id="child">
   <input type="text" v-model="post.msg" v-on:input="updateValue()">
</template>
3
Perlovka

もっと簡単な方法はthis.$emitを使うことです

Father.vue

<template>
  <div>
    <h1>{{ message }}</h1>
    <child v-on:listenerChild="listenerChild"/>
  </div>
</template>

<script>
import Child from "./Child";
export default {
  name: "Father",
  data() {
    return {
      message: "Where are you, my Child?"
    };
  },
  components: {
    Child
  },
  methods: {
    listenerChild(reply) {
      this.message = reply;
    }
  }
};
</script>

Child.vue

<template>
  <div>
    <button @click="replyDaddy">Reply Daddy</button>
  </div>
</template>

<script>
export default {
  name: "Child",
  methods: {
    replyDaddy() {
      this.$emit("listenerChild", "I'm here my Daddy!");
    }
  }
};
</script>

私の全例: https://codesandbox.io/s/update-parent-property-ufj4b

0