vuejs更新子组件的父数据

时间:2016-12-01 16:16:13

标签: javascript vue.js vue-component

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

如何正确更新组件的父数据? 从父级传递绑定的prop并不好,并向控制台发出一些警告。他们的文档中有一些东西,但它不起作用。

16 个答案:

答案 0 :(得分:123)

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>
&#13;
&#13;
&#13;

文档声明

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

相当于

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

这就是为什么孩子的道具需要被命名为值,以及为什么孩子需要$发出名为input的事件。

答案 1 :(得分:92)

来自documentation

  

在Vue.js中,父子组件关系可以概括为道具向下,事件向上。父母通过道具将数据传递给孩子,孩子通过事件向父母发送消息。让我们看看他们接下来的工作方式。

enter image description here

How to pass props

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

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

How to emit event

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

答案 2 :(得分:19)

在子组件中: this.$emit('eventname', this.variable)

在父组件中:

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

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

答案 3 :(得分:4)

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

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

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

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

documentation的意思是:

  

在某些情况下,我们可能需要对道具进行“双向绑定”。   不幸的是,真正的双向绑定会造成维护问题,   因为子组件可以在没有源的情况下改变父组件   这种变异在父母和孩子中都很明显。

     

这就是为什么我们建议以以下方式发出事件:   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>

您还可以通过发送一个对象来一次同步多个对象。查看documentation here

答案 4 :(得分:3)

也可以将props作为Object或Array传递。在这种情况下,数据将是双向绑定的:

(主题末尾注明:https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow

&#13;
&#13;
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;
    }
  }
});
&#13;
<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>
&#13;
&#13;
&#13;

答案 5 :(得分:1)

子组件

使用this.$emit('event_name')将事件发送到父组件。

enter image description here

父组件

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

enter image description here

完成:)

答案 6 :(得分:1)

在孩子中

 <input
            type="number"
            class="form-control"
            id="phoneNumber"
            placeholder
            v-model="contact_number"
            v-on:input="(event) => this.$emit('phoneNumber', event.target.value)"
    />

data(){
    return {
      contact_number : this.contact_number_props
    }
  },
  props : ['contact_number_props']

在父级

<contact-component v-on:phoneNumber="eventPhoneNumber" :contact_number_props="contact_number"></contact-component>


 methods : {
     eventPhoneNumber (value) {
      this.contact_number = value
    }

答案 7 :(得分:1)

2021 答案 - 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)
    }
  }
}

长话短说:实际上,子组件的更改正在 $emitted 并更新父组件的 dataForm.memmbers[]。

来源:Mauro Perez at medium

答案 8 :(得分:0)

更简单的方法是使用heightAnchor

Father.vue

this.$emit

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

我的完整示例:https://codesandbox.io/s/update-parent-property-ufj4b

答案 9 :(得分:0)

正确的方法是$emit() an event in the child component that the main Vue instance listens for

resolvers += Resolver.url("my-test-repo", new java.net.URL("https://dl.bintray/blocke/releases"))(Resolver.mavenStylePatterns)

答案 10 :(得分:0)

我不知道为什么,但是我只是使用数据作为对象:setcomputed

成功地更新了父数据

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;

            },
        }

答案 11 :(得分: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
    });
}

答案 12 :(得分:0)

我认为这可以解决问题:

@change="$emit(variable)"

答案 13 :(得分:0)

在父级中->

data : function(){
            return {
                siteEntered : false, 
            };
        },

在子组件中->

this.$parent.$data.siteEntered = true;

答案 14 :(得分:0)

介绍

我正在寻找在 vue3 中从父级到子级(并返回)发送数据(我知道问题是关于 vue2,但当时在 SO 上没有关于 vue3 的参考)。

以下是工作样板结果,纯“html + js”,没有打包程序、模块等,我有一些警告,解释。

注意事项:

  1. 插入子行 <块引用>
    <component-a :foo="bar" @newfooevent="bar = $event"></component-a>`
    
  • 我使用简写 parent.barchild.foo 绑定到 :foo="bar",与 v-bind:foo="bar" 相同。它通过 props 将数据从 parent 传递给 child。

  • 警告:事件侦听器应仅放置在子组件标记中!

    那是 @newfooevent="bar = $event" 部分。

    您无法在 <div id="app"> 或父级内部的任何其他地方捕获信号。

    尽管如此,这是宇宙的父方,在这里您可以访问所有父的数据并从子信号中提取数据进行处理。

  1. 您可以创建应用程序,并在其之后定义组件(app.component("component-a", ...) 部分。

    警告:不需要组件的前向声明,例如C/C++ 中的函数。您可以创建使用该组件的应用程序,然后定义该组件。我花了很多时间寻找以某种方式声明它的方法 - 没有必要。

  2. 您可以在此处找到一个很好的 v-model 用法示例,以及我用来解决问题的代码:https://javascript.plainenglish.io/vue-3-custom-events-d2f310fe34c9

例子

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <meta charset="utf-8" />
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <component-a :foo="bar" @newfooevent="bar = $event"></component-a>
      <p>Parent copy of `bar`: {{ bar }}</p>
      <button @click="bar=''">Clear</button>
    </div>

    <script>
      const app = Vue.createApp({
        data() {
          return {
            bar: "bar start value"
          };
        }
      });      

      app.component("component-a", {
        props: {
          foo: String
        },
        template: `
          <input 
            type="text"
            :value="foo"
            @input="$emit('newfooevent', $event.target.value)">
        `
      });      

      app.mount("#app");
    </script>
  </body>
</html>

答案 15 :(得分:-1)

另一种方法是将设置器的引用作为属性从父级传递给子级组件,类似于他们在React中的操作。 假设您在父级上有一个方法updateValue用于更新值,您可以像这样{@ {1}}来实例化子级组件。然后在孩子上,您将有一个对应的道具:<child :updateValue="updateValue"></child>,并且在输入更改为props: {updateValue: Function}时在模板中调用方法。