vuejs从子组件更新父数据


155

我开始玩vuejs(2.0)。我构建了一个包含一个组件的简单页面。该页面具有一个带有数据的Vue实例。在该页面上,我注册了该组件并将其添加到html中。该组件有一个input[type=text]。我希望该值反映在父对象(主Vue实例)上。

如何正确更新组件的父数据?从父级传递绑定的道具不好,并且会向控制台发出一些警告。他们的文档中有内容,但是没有用。


1
您可以添加您尝试过的代码吗,它无法正常工作。
萨拉巴

Answers:


181

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>

这就是为什么需要将子项上的prop命名为value的原因,以及子项需要$ emit发出名为的事件的原因input


首先感谢您的答复。您可以扩展一下,还是更好地指向有关“输入”事件的文档?似乎是一个内置事件。
Gal Ziv

我添加了一个说明,并使指向文档的链接更加明显。
asemahle '16

1
我省略了组件和创建的函数的属性“值”,它仍然有效。您能解释一下为什么使用它吗?
xetra11

1
如果您不添加道具,那么它将undefined直到第一次更改。看到我评论过的这个小提琴props: ['value']。注意初始值是如何undefined,而不是hellojsfiddle.net/asemahle/8Lrkfxj6。第一次更改后,Vue会为组件动态添加一个值道具,因此它可以工作。
asemahle

我在文档中阅读了此内容。很好的例子。如果可以的话,+ 10!
粘土

121

文档中

在Vue.js中,父子组件关系可以概括为道具下降,事件上升。父级通过道具将数据传递给子级,而子级则通过事件向父级发送消息。让我们看看它们接下来如何工作。

在此处输入图片说明

如何传递道具

以下是将prop传递给子元素的代码:

<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
    }
  }
})

5
如果函数“ increment”位于父组件中,而我想从子组件中触发该怎么办?
Hamzaouiii

抓紧概念的瞬间,尽管已经被hacky复制粘贴多次使用了……
Yordan Georgiev '18

1
我将打印该图形并将其粘贴到我的头上。谢谢!
domih,

1
在此示例中,我们不应该在根组件中定义一个事件侦听器吗?类似的东西:```Mounted(){this.on('increment',()=> {this.incrementTotal();}); }```
jmk2142

94

在子组件中:

this.$emit('eventname', this.variable)

在父组件中:

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

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

3
这个例子让我震惊。你不知道我来这里之前经历了多少教程...
–suchislife

18

子组件

使用this.$emit('event_name')发送事件到母部件。

在此处输入图片说明

父组件

为了在父组件中监听该事件,我们执行v-on:event_name了一个ex. handleChange要在该事件上执行的方法()

在此处输入图片说明

完成:)


13

我同意上述情况的事件发出和v模型答案。但是,我以为我会发布我发现的有关具有多个表单元素的组件的信息,这些组件想要发回给它们的父对象,因为这似乎是google返回的第一篇文章之一。

我知道这个问题指定了单个输入,但是这似乎是最接近的匹配,并且可以通过类似的vue组件为人们节省一些时间。另外,还没有人提到.sync修饰符。

据我所知,该v-model解决方案仅适用于返回其父级的一个输入。我花了一些时间寻找它,但Vue(2.3.0)文档确实显示了如何将发送到组件中的多个道具同步回父对象(当然是通过发出)。

它被适当地称为.sync修饰符。

这里是什么文件说:

在某些情况下,我们可能需要对道具进行“双向绑定”。不幸的是,真正的双向绑定可能会造成维护问题,因为子组件可以使父项发生变异,而在父项和子项中均不明显该变异的来源。

因此,我们建议您以的模式发出事件 update:myPropName。例如,在带有titleprop 的假设组件中 ,我们可以通过以下方式传达分配新值的意图:

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>

您也可以通过发送一个对象来一次同步多个对象。在此处查看文档


这就是我想要的。非常感谢。
汤玛斯

截至2020年,这是最好,最新的解决方案。非常感谢!
马塞洛

6

使用更简单的方法 this.$emit

父亲

<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>

小孩

<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


5

也可以将prop作为对象或数组传递。在这种情况下,数据将被双向绑定:

(这在主题末尾注明: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>


1

正确的方法是处理$emit()主Vue实例侦听的子组件中的事件

// Child.js
Vue.component('child', {
  methods: {
    notifyParent: function() {
      this.$emit('my-event', 42);
    }
  }
});

// Parent.js
Vue.component('parent', {
  template: '<child v-on:my-event="onEvent($event)"></child>',
  methods: {
    onEvent: function(ev) {
      v; // 42
    }
  }
});

0

1)子组件:您可以在子组件中像这样使用:this.formValue将一些数据发送到父组件

this.$emit('send',this.formValue)

2)Parrent Compnenet:并且在parrent组件标签中接收如下发送变量:这是用于接收父组件标签中的子组件数据的代码

@send="newformValue"

0

另一种方法是将设置器的引用从父级传递为子组件的道具,类似于他们在React中的操作。假设您updateValue在父级上有一个更新值的方法,则可以实例化子级组件,如下所示:<child :updateValue="updateValue"></child>。然后在子级上,您将有一个对应的prop:,props: {updateValue: Function}并且在模板中,当输入更改时调用方法:<input @input="updateValue($event.target.value)">


0

我不知道为什么,但我只是成功更新父数据使用的数据为研究对象,:setcomputed

亲子

<!-- check inventory status - component -->
    <CheckInventory :inventory="inventory"></CheckInventory>

data() {
            return {
                inventory: {
                    status: null
                },
            }
        },

小孩

<div :set="checkInventory">

props: ['inventory'],

computed: {
            checkInventory() {

                this.inventory.status = "Out of stock";
                return this.inventory.status;

            },
        }

0

他的示例将告诉您如何在“提交”按钮上将输入值传递给父对象。

首先将eventBus定义为新的Vue。

//main.js
import Vue from 'vue';
export const eventBus = new Vue();

Pass your input value via Emit.
//Sender Page
import { eventBus } from "../main";
methods: {
//passing data via eventbus
    resetSegmentbtn: function(InputValue) {
        eventBus.$emit("resetAllSegment", InputValue);
    }
}

//Receiver Page
import { eventBus } from "../main";

created() {
     eventBus.$on("resetAllSegment", data => {
         console.log(data);//fetching data
    });
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.