vuejs更新子组件的父数据

Gal*_*Ziv 106 javascript vue.js vue-component

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

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

ase*_*hle 139

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'
  }
});
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


文档说明了这一点

<custom-input v-bind:value="something" v-on:input="something = arguments[0]"></custom-input>
Run Code Online (Sandbox Code Playgroud)

相当于

<custom-input v-model="something"></custom-input>
Run Code Online (Sandbox Code Playgroud)

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

  • 我添加了一个说明,并使文档的链接更加明显。 (2认同)
  • 我省略了组件和创建的函数的道具“值”,但它仍然有效。你能解释一下你为什么使用它吗? (2认同)
  • 如果您不添加该道具,则在第一次更改之前它将是“未定义”。看到这个小提琴,我已经注释掉了`props: ['value']`。注意初始值如何是 `undefined`,而不是 `hello`:https://jsfiddle.net/asemahle/8Lrkfxj6/。第一次更改后,Vue 动态地为组件添加了一个 value 属性,因此它可以工作。 (2认同)

Sau*_*abh 103

文档:

在Vue.js中,父子组件关系可以概括为道具向下,事件向上.父母通过道具将数据传递给孩子,孩子通过事件向父母发送消息.让我们看看他们下一步如何运作.

在此输入图像描述

如何传递道具

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

<div>
  <input v-model="parentMsg">
  <br>
  <child v-bind:my-message="parentMsg"></child>
</div>
Run Code Online (Sandbox Code Playgroud)

如何发射事件

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>
Run Code Online (Sandbox Code Playgroud)

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
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

  • 如果函数'增量'在父组件中并且我想从子组件触发它怎么办? (4认同)
  • 在这个例子中,我们不应该在根组件中定义一个事件监听器吗?类似于: ``` Mounted() { this.on('increment', () =&gt; { this.incrementTotal(); }); } ``` (2认同)

Sar*_*oev 47

在子组件中: __CODE__

在父组件中:

this.$emit('eventname', this.variable)
Run Code Online (Sandbox Code Playgroud)

  • 这个例子让我大吃一惊。你不知道在我来到这里之前我经历了多少教程...... (13认同)
  • 非常简单明了。谢谢。 (8认同)
  • 那很棒。简单明了。谢谢。 (2认同)

Dar*_*ich 12

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

父亲.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>
Run Code Online (Sandbox Code Playgroud)

儿童.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>
Run Code Online (Sandbox Code Playgroud)

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


小智 10

子组件

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

在此处输入图片说明

父组件

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

在此处输入图片说明

完成:)


Ron*_*n16 7

在父组件中 -->

data : function(){
            return {
                siteEntered : false, 
            };
        },
Run Code Online (Sandbox Code Playgroud)

在子组件中 -->

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


Per*_*vka 6

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

(这在主题末尾注明: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;
    }
  }
});
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


小智 6

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

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

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

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

这里是什么文件说:

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

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

this.$emit('update:title', newTitle)
Run Code Online (Sandbox Code Playgroud)

然后,如果需要,父级可以侦听该事件并更新本地数据属性。例如:

<text-document   
 v-bind:title="doc.title"  
 v-on:update:title="doc.title = $event"
></text-document>
Run Code Online (Sandbox Code Playgroud)

为了方便起见,我们使用.sync修饰符为该模式提供了一个简写形式:

<text-document v-bind:title.sync="doc.title"></text-document>
Run Code Online (Sandbox Code Playgroud)

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


Des*_*web 5

2021 年答案 - Vue 2.3+

简短回答:只需.sync在父级中添加修饰符并将数据作为 props 传递给子级:

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

Run Code Online (Sandbox Code Playgroud)

嵌套子组件: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)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

长话短说:子组件的更改实际上正在 $emit 并更新formData.members[]父组件。

资料来源:Mauro Perez,媒体