Vuejs:如何将对象作为道具传递并让组件更新子对象

新手上路,请多包涵

我正在尝试创建一个组件,它接受一个对象作为道具,并且可以修改该对象的不同属性并将值返回给父级,使用同步或发出事件。该示例将不起作用,但它只是为了演示我要实现的目标。

这是我要实现的目标的片段:

 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) {
      //Not sure if both fields should call the same updateValue method that returns the complete object, or if they should be separate
      this.$emit('input', value);
    }
  }
});

new Vue({
  el: '#app',
  data: {
    parentObject: {value1: "1st Value", value2: "2nd value"}
  }
});
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>

<div id="app">
  <p>Parent value: {{parentObject}}</p>
  <child v-model="parentObject"></child>
</div>

<template id="child">
   <input type="text" v-bind:value.value1="value" v-on:input="updateValue($event.target.value)">
   <input type="text" v-bind:value.value2="value" v-on:input="updateValue($event.target.value)">
</template>

原文由 Storm 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 336
2 个回答

您不应该修改作为道具传入的对象。相反,您应该在子组件中创建一个新的数据属性,并使用 prop 对象的副本对其进行初始化。

然后,我将只对子组件中的每个输入使用 v-model ,并向内部值添加一个深度观察器,只要内部值发生变化,它就会发出 update

 Vue.component('child', {
  template: '#child',
  props: ['value'],
  data() {
    return { val: {...this.value} };
  },
  watch: {
    val: {
      deep: true,
      handler(value) {
        this.$emit('input', value);
      }
    }
  }
});

new Vue({
  el: '#app',
  data: {
    parentObject: {value1: "1st Value", value2: "2nd value"}
  }
});
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>

<div id="app">
  <p>Parent value: {{parentObject}}</p>
  <child v-model="parentObject"></child>
</div>

<template id="child">
  <div>
    <input type="text" v-model="val.value1">
    <input type="text" v-model="val.value2">
  </div>
</template>

我在我的示例 ( {...this.value} ) 中制作了一个 prop 的浅表副本,因为该对象没有任何嵌套属性。如果不是这种情况,您可能需要进行深层复制 ( JSON.parse(JSON.stringify(this.value)) )。

原文由 thanksd 发布,翻译遵循 CC BY-SA 3.0 许可协议

#app 中,应该是 parentObject ,而不是 parentValue

在孩子中,您有两个 inpyt ,但您必须有一个根元素。在下面的示例中,我为组件创建了一个 <div> 根元素。

要更新父级,请发出事件。这种方法不会修改父项在子项中的属性,因此不会中断单向数据流。

 Vue.component('child', {
  template: '#child',

  //The child has a prop named 'value'. v-model will automatically bind to this prop
  props: ['value']
});

new Vue({
  el: '#app',
  data: {
    parentObject: {value1: "1st Value", value2: "2nd value"}
  }
});
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>

<div id="app">
  <p>Parent value: {{parentObject}}</p>
  <child v-model="parentObject"></child>
</div>

<template id="child">
<div>
   <input type="text" v-bind:value="value.value1" v-on:input="$emit('input', {value1: $event.target.value, value2: value.value2})">
   <input type="text" v-bind:value="value.value2" v-on:input="$emit('input', {value1: value.value1, value2: $event.target.value})">
</div>
</template>

关于 <input> s:您可以将每个绑定到父级的属性 value 。然后,在编辑时,发出一个事件,仅修改该属性 ( v-on:input="$emit('input', {value1: $event.target.value, value2: value.value2}) ) 并保留另一个的值。父母因此更新。

如果你有很多属性,你可以在第二个 input 替换,例如:

 $emit('input', {value1: value.value1, value2: $event.target.value})

$emit('input', Object.assign({}, value, {value2: $event.target.value}))

使用方法而不是直接从模板发出

我保留了之前的演示,因为它更直接、更容易理解(与原始代码相比更改更少),但更紧凑的方法是使用方法(例如 updateValue )并在模板中重用它:

 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(propertyName, propertyValue) {
      this.$emit('input', Object.assign({}, this.value, {[propertyName]: propertyValue}))
    }
  }
});

new Vue({
  el: '#app',
  data: {
    parentObject: {value1: "1st Value", value2: "2nd value"}
  }
});
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>

<div id="app">
  <p>Parent value: {{parentObject}}</p>
  <child v-model="parentObject"></child>
</div>

<template id="child">
<div>
  <input type="text" v-bind:value="value.value1" v-on:input="updateValue('value1', $event.target.value)">
  <input type="text" v-bind:value="value.value2" v-on:input="updateValue('value2', $event.target.value)">
</div>
</template>

如您所见,上面的演示已经使用了 Object.assign() ,这意味着它将处理无限数量的属性。

原文由 acdcjunior 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题