我开始玩vuejs(2.0)。 我构建了一个包含一个组件的简单页面。 该页面有一个带有数据的Vue实例。 在那个页面上,我注册并将组件添加到html中。 组件有一个输入[type=text]。我希望该值反映在父实例(主Vue实例)上。
如何正确地更新组件的父数据? 从父对象传递绑定道具是不好的,会向控制台抛出一些警告。他们的文件里有一些东西,但不管用。
我开始玩vuejs(2.0)。 我构建了一个包含一个组件的简单页面。 该页面有一个带有数据的Vue实例。 在那个页面上,我注册并将组件添加到html中。 组件有一个输入[type=text]。我希望该值反映在父实例(主Vue实例)上。
如何正确地更新组件的父数据? 从父对象传递绑定道具是不好的,会向控制台抛出一些警告。他们的文件里有一些东西,但不管用。
当前回答
更简单的方法是使用这个。$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
其他回答
双向绑定在Vue 2.0中已弃用,转而使用事件驱动的体系结构。一般来说,孩子不应该改变它的道具。相反,它应该$emit事件并让父进程响应这些事件。
在您的特定情况下,您可以使用带有v-model的自定义组件。这是一种特殊的语法,它允许一些接近双向绑定的东西,但实际上是上面描述的事件驱动体系结构的简写。你可以在这里阅读-> https://v2.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,以及为什么子对象需要$emit一个名为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
}
}
})
2021 ANSWER - Vue 2.3+
简单回答:只需在父类中添加.sync修饰符,并将数据作为道具传递给子类:
// PARENT:
data () {
return {
formData: {
members: [] //<- we wanna pass this one down to children and add/remove from the child component
}
}
// PARENT TEMPLATE:
<!-- ADD MEMBERS -->
<add-members :members.sync="formData.members" />
嵌套子组件:AddMembers.vue
export default {
name: 'AddMembers',
props: ['members'],
methods: {
addMember () {
this.members.push(new Member()) // <-- you can play and reactivity will work (in the parent)
},
removeMember (index) {
console.log('remove', index, this.members.length < 1)
this.members.splice(index, 1)
}
}
}
说来话长:实际上,来自子组件的更改被$发出并更新formData。父类的成员[]。
来源:Mauro Perez at medium
我不知道为什么,但我刚刚成功地更新了使用数据作为对象的父数据,:set & computed
Parent.vue
<!-- check inventory status - component -->
<CheckInventory :inventory="inventory"></CheckInventory>
data() {
return {
inventory: {
status: null
},
}
},
Child.vue
<div :set="checkInventory">
props: ['inventory'],
computed: {
checkInventory() {
this.inventory.status = "Out of stock";
return this.inventory.status;
},
}
也可以将道具作为对象或数组传递。在这种情况下,数据将是双向绑定的:
(这一点在主题的最后注明:https://v2.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>