【问题标题】:VueJS best practices for passing form-data to child and back to parentVueJS 将表单数据传递给子级并返回给父级的最佳实践
【发布时间】:2020-05-16 11:06:08
【问题描述】:

我正在开发一个 VueJS 项目,并且有这样的父/子组件。

Parent.vue

<template>
    <ChildA v-bind="this.postData.someDataA" />
    ...
    <ChildZ v-bind="this.postData.someDataZ"/>
    <button @click="save">Save</button>
</template>

<script>
    import ChildA from './ChildA';
    ...
    import ChildZ from '.ChildZ';
    data() {
    return {
        postData: {
            someDataA: {field1: 'initialValue'}
            someDataB: { // no initial value'}
            ...
        },
    },
    methods: {
        save() {this.$root.db.save(this.postData)}
    }
</script>

Child.vue

<template>
    <input type="text" v-model="field1" />
    ...
    <input type="text" v-model="field10" />
</template>

<script>
    props: {
        field1:{type: String, default: 'default if not set by parent'},
        ...
    }
</script>

如您所见,我想将 this.postDataParent.vue 传递给将其保存到数据库的函数。但是,someDataA 等的值来自Child.vue

当我像这样运行我的代码时,我收到了 Vue 警告:

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders.

现在,我的问题是,处理这种情况的最佳做法是什么?我是否必须为每个子元素实现&lt;ChildA @change="setSomeDataA()" /&gt;,并且每次子道具的值发生变化时$emit 一个事件?

【问题讨论】:

  • 有时我更喜欢使用this.$parent从孩子那里访问父数据
  • 但是你不应该在子组件中使用 props 作为 v-model 值
  • 请查看answer
  • @ChristianCarrillo 我应该怎么做呢?如果我想在Child.vue中修改someDataA

标签: vue.js


【解决方案1】:

设置您的孩子使用 v-model,然后使用 emit 更改。例如:

父母使用v-model呼叫孩子

Parent.vue

<template>
    <ChildA v-model="this.postData.someDataA" />
    ...
    <ChildZ v-model="this.postData.someDataZ"/>
    <button @click="save">Save</button>
</template>

<script>
    import ChildA from './ChildA';
    ...
    import ChildZ from '.ChildZ';
    data() {
    return {
        postData: {
            someDataA: {field1: 'initialValue'}
            someDataB: { // no initial value'}
            ...
        },
    },
    methods: {
        save() {this.$root.db.save(this.postData)}
    }
</script>

孩子接受value 的属性并将内部变量设置为value。您的输入使用内部变量,因为它是 v-model。然后使用@change 或观察者emit('input', &lt;your internal variable&gt;)

Child.vue

<template>
    <input type="text" @change="objChanged" v-model="myObj.field1" />
    ...
    <input type="text" @change="objChanged" v-model="myObj.field10" />
</template>

<script>
    props: {
        value:{type: String, default: 'wont need a default'},
        ...
    },
    data: {
        myObj: {}
    },
    methods: {
        objChanged(){
            this.$emit('input', this.myObj);
        }
    },
    created(){
        this.myObj = this.value;
    }
</script>

【讨论】:

  • 为了简化事情,我可以deep-watchmyObj 并发出事件吗?
  • @ad_on_is,是的,我提到你可以使用观察者
  • 哦,抱歉...没看到 ;-)
  • 如果父组件的 prop 发生变化会怎样?
  • @EmīlsGulbis 那么它在子组件处发生了变化?想想 v-model 是如何工作的,如果另一个组件修改了 prop,它会相应地更新
【解决方案2】:

实际上最好制作计算属性,而不是使用 value 属性的副本。

props: {
  value: {
    type: Object,
    default: () => ({})
  }
},

computed: {
  field1: {
    get() { return this.value.field1 },
    set(field1) { this.$emit('input', {...this.value, field1 })}
  }
}

然后像这样使用它

<input type="text" v-model="field1" />

【讨论】:

  • 好的,我把它分开了,如果 prop 可能从父级更改,这是一个更好的方法。
猜你喜欢
  • 2016-11-14
  • 1970-01-01
  • 1970-01-01
  • 2017-08-23
  • 2020-09-22
  • 2021-05-21
  • 2021-06-29
  • 2011-09-07
  • 1970-01-01
相关资源
最近更新 更多