如何使用从孩子传递给父母的v模型和道具?

时间:2019-10-17 10:26:18

标签: vue.js

我学习vue已有几天了,我正在尝试在父母之间传递数据/道具。 现在,我有以下孩子:

<template>
  <div>
    <input v-model="name1" placeholder="string">
    <input v-model="number1" placeholder="number">
    <p v-text="name1"></p>
    <p v-text="number1"></p>
  </div>
</template>

<script>
export default {
  name: "child",
  props: {
    name1 : String,
    number1 : Number
  }
}
</script>

然后是父级:

<template>
  <div>
    <child/>
  </div>
</template>

<script>
import child from "@/components/complexComponent4/child.vue"

export default{
  name: "parent",
  components: {
    child
  }
}
</script>

现在,当我在输入字段中输入一些文本时,它会正确显示在段落中,因为绑定到段落的道具已更改。 但是,我收到此警告:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "name1"

found in

---> <Child>
       <Parent> at src/components/complexComponent4/parent.vue
         <MyComplexView4.vue> at src/views/myComplexView4.vue
           <App> at src/App.vue
             <Root>

我在互联网上的许多地方以及文档中都读到了有关此错误的信息,我发现现在将muting props视为反模式: https://michaelnthiessen.com/avoid-mutating-prop-directly

不幸的是,我没有真正发现任何特定的东西和/或对如何解决这个问题没有帮助。特别是在vue上下文中,以不同方式处理原始数据和对象/数组(对象/数组通过引用传递)。

v型模型似乎在利用vue的力量方面起着重要作用,因为它启用了双向绑定。因此,我不想完全省略它,除非它的使用变得如此困难,以致不能证明其收益。

3 个答案:

答案 0 :(得分:2)

如警告所述,您应该避免在子组件中直接对道具 进行突变。 因此,您应该从子级向父级发出一个事件,以使父级知道prop值已更改。父母会更改道具并将其传递给孩子。

为此,Vue中有一种语法糖,称为.sync修饰符。

所以您的组件可能是这样的。 孩子:

<template>
  <div>
    <input 
      :value="name1" 
      @change="$emit('update:name1', $event.target.value)"
      placeholder="string"
    />
    <input 
      :value="number1" 
      @change="$emit('update:number1', $event.target.value)" 
      placeholder="number"
    />
    <p v-text="name1"></p>
    <p v-text="number1"></p>
  </div>
</template>

<script>
export default {
  name: "child",
  props: {
    name1 : String,
    number1 : Number
  }
}
</script>

和父母:

<template>
  <div>
    <child :name1.sync="name1" :number1.sync="number1"/>
  </div>
</template>

<script>
import child from "@/components/complexComponent4/child.vue"

export default{
  name: "parent",
  components: {
    child
  },
  data() {
    return {
      name1: '',
      number1: ''
    }
  }
}
</script>

或者对于更复杂的情况,您可以在子组件中使用v-model和带有setter的计算属性:

<template>
  <div>
    <input 
      v-model="computedName1" 
      placeholder="string"
    />
    <input 
      v-model="computedNumber1" 
      placeholder="number"
    />
    <p v-text="name1"></p>
    <p v-text="number1"></p>
  </div>
</template>

<script>
export default {
  name: "child",
  props: {
    name1 : String,
    number1 : Number
  },
  computed: {
    computedName1: {
      get() { return this.name1 },
      set(value) {
        // some logic
        this.$emit('update:name1', value)
      },
    computedNumber1: {
      get() { return this.number1 },
      set(value) {
        // some logic
        this.$emit('update:number1', value)
      }
    }
  }
}
</script>

答案 1 :(得分:1)

如果您打算更改传递给子对象的prop,请先将其分配给子数据。

<template>
  <div>
    <input v-model="name" placeholder="string">
    <input v-model="number" placeholder="number">
    <p v-text="name"></p>
    <p v-text="number"></p>
  </div>
</template>

<script>
export default {
  name: "child",
  data() {
    return {
      name: null,
      number: null
    }
  },
  props: {
    name1 : String,
    number1 : Number
  },
  mounted() {
    this.name = this.name1;
    this.number = this.number1;
  }
}
</script>

更改数据后,您可以将这些更改发送给父组件

  1. 具有同步

父母

<child :number1.sync="number1" :name1.sync="name1" />

孩子

watch: {
    name: value => this.$emit('update:name1', value)
    number : value => this.$emit('update:number1', value)
  },
  1. 具有事件

父母

<child :number1="number1" :name1="name1" @changeNumber="value => number1 = value" @changeName="value => name1 = value" />

孩子

watch: {
    name: value => this.$emit('changeName', value)
    number : value => this.$emit('updateNumber', value)
  },

答案 2 :(得分:0)

vue.js的准则是,您可以使用道具自动更改父级中子级中的数据,反之亦然。为了改变父组件的数据,子组件应该使用事件。您可以考虑分别为name1和number1使用两个不同的组件,并通过使这些组件适用于v-model(如here所述)以双向方式绑定值。