Vuejs обновляет родительские данные из дочернего компонента
Я начинаю играть с vuejs (2.0). Я построил простую страницу с одним компонентом. На странице есть один экземпляр Vue с данными. На этой странице я зарегистрировался и добавил компонент в HTML. Компонент имеет один input[type=text]
. Я хочу, чтобы это значение отражалось на родителе (основной экземпляр Vue).
Как правильно обновить родительские данные компонента? Передача привязанного реквизита от родителя не годится и выдает некоторые предупреждения на консоль. У них есть что-то в их документе, но это не работает.
Ответы
Ответ 1
Двусторонняя привязка в Vue 2.0 устарела в пользу использования более управляемой событиями архитектуры. В общем, ребенок не должен мутировать свои реквизиты. Скорее, он должен $emit
events и позволить родителю отвечать на эти события.
В вашем конкретном случае вы можете использовать пользовательский компонент с 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>
Ответ 2
Из документации:
В 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
}
}
})
Ответ 3
В дочернем компоненте: this.$emit('eventname', this.variable)
В родительском компоненте:
<component @eventname="updateparent"></component>
methods: {
updateparent(variable) {
this.parentvariable = variable
}
}
Ответ 4
Я согласен с ответами о событиях и V-модели для тех, кто выше. Тем не менее, я подумал, что опубликую то, что я нашел, о компонентах с несколькими элементами формы, которые хотят отправить обратно своим родителям, так как это кажется одной из первых статей, возвращаемых Google.
Я знаю, что в вопросе указывается один вход, но это кажется самым близким совпадением и может сэкономить людям некоторое время с подобными компонентами vue. Также еще никто не упомянул модификатор .sync
.
Насколько я знаю, решение v-model
подходит только для одного входа, возвращаемого их родителю. Я потратил немного времени на его поиск, но документация 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>
Вы также можете синхронизировать несколько одновременно, посылая через объект. Проверьте документацию здесь
Ответ 5
Дочерний компонент
Используйте this.$emit('event_name')
чтобы отправить событие в родительский компонент.
![enter image description here]()
Родительский компонент
Чтобы прослушать это событие в родительском компоненте, мы делаем v-on:event_name
и происходит метод (ex. handleChange
), который мы хотим выполнить для этого события.
![enter image description here]()
Готово :)
Ответ 6
Также возможно передавать реквизиты как объект или массив. В этом случае данные будут двусторонне связаны:
(Это отмечено в конце темы: https://vuejs.org/v2/guide/components.html#One-Way-Data-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>
Ответ 7
Более простой способ - использовать 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