如何使用从孩子传递给父母的 v-model 和 props?

Nar*_*tor 3 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>
Run Code Online (Sandbox Code Playgroud)

然后是父级:

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

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

export default{
  name: "parent",
  components: {
    child
  }
}
</script>
Run Code Online (Sandbox Code Playgroud)

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

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

我在互联网上的多个地方以及文档中读到了这个错误,我发现变异道具现在被认为是一种反模式: https: //michaelnthiessen.com/avoid-mutating-prop-directly

不幸的是,我并没有真正找到任何关于如何处理这个问题的具体和/或有用的信息。特别是在 vue 以不同方式处理原始数据和对象/数组的情况下(对象/数组通过引用传递)。

v-model 似乎在利用 vue 的强大功能方面发挥着重要作用,因为它支持双向绑定。因此,我不想完全忽略它,除非它的使用变得如此困难,以至于无法证明其收益是合理的。

Eli*_*ski 10

正如警告所述,您应该避免直接在子组件中改变 props。因此,您应该从子级向父级发出一个事件,让父级知道 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>
Run Code Online (Sandbox Code Playgroud)

和家长:

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

或者,对于更复杂的情况,您可以在子组件中使用 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>
Run Code Online (Sandbox Code Playgroud)