私はvuejs(2.0)で遊び始めています。 1つのコンポーネントを含む単純なページを作りました。ページにはデータを含む1つのVueインスタンスがあります。そのページで私はHTMLにコンポーネントを登録して追加しました。コンポーネントにはinput[type=text]
が1つあります。その値を親(メインのVueインスタンス)に反映させたい。
コンポーネントの親データを正しく更新する方法親からバインドされたプロップを渡すことは良くありませんし、コンソールにいくつかの警告を投げます。彼らは彼らのドキュメントに何かを持っていますが、それはうまくいきません。
双方向バインディングは、イベント駆動型のアーキテクチャーを採用するため、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
という名前のイベントを子が$発行する必要がある理由です。
Vue.jsでは、親子コンポーネントの関係は、小道具が下がり、イベントが上がるようにまとめることができます。親は小道具を介して子にデータを渡し、子はイベントを介して親にメッセージを送信します。次にそれらがどのように機能するのかを見てみましょう。
以下は子要素に小道具を渡すコードです。
<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
}
}
})
子コンポーネント内:this.$emit('eventname', this.variable)
親コンポーネント内:
<component @eventname="updateparent"></component>
methods: {
updateparent(variable) {
this.parentvariable = variable
}
}
上記のものに対するイベント発行および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>
オブジェクトを介して送信することで、一度に複数を同期することもできます。ここで ドキュメントをチェックしてください
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>
もっと簡単な方法は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>