东林博客

Vue父组件往子组件v-model传值报错

随着做的SPA应用越来越多,项目越来越大。书读百遍其义自见,对Vue的设计理解的也越来越深刻。从之前照猫画虎,到现在已领会到Compoents的强大之处。无处不可组件,无处不是组件。虽然Components就是组件的意思,但真正领会到这一点,确实有点道可道,非常道的感觉。

Vue 父组件表单调用一个子组件,类似后端的功能封装。利用巧妙的业务解耦,在一个后台业务中,可以独立出很多小巧可复用的组件。前期设计和微调这些小组件会慢一些,但越做越快,呈指数增长,且整个SPA应用架构良好,扩展性强。

目前在一个父组件表单中,调用一个自己封装的业务下拉框 ROAM,可多选,可单选。代码如下:

父组件:

<tm-roam v-model="form.roam" :multiple="true"></tm-roam>

子组件:

<template>
    <el-select :style="style" v-model="value" multiple placeholder="请选择">
        <el-option
                v-for="item in options"
                :key="item"
                :label="item"
                :value="item">
        </el-option>
    </el-select>
</template>

<script>
    export default {
        name: "TmRoam",
        props:{
            value:{
                type:Array
            },
            multiple:{
                type:Boolean,
                default:false
            },
            limit:{
                type:Number,
                default: 1,
            }
        },
        model:{
            prop:'value',
            event:'returnBack'
        },
        data() {
            return {
                options:['转让','出租', '转包', '合作', '入股', '互换', '招拍挂'],
            }
        },
        computed:{
            style(){
                if(this.multiple){
                    return 'min-width: 380px'
                }
            }
        },
        created() {

        },
        methods: {
            returnBack(){

            }
        }
    }
</script>

<style>

</style>

页面效果:

每当我选择了所属类型,流转方式(子组件ROAM)选择好的值就会自动清空。观察Vue状态,选择流转方式(选择子组件)时,子组件的 value值并不能实时同步到父组件的form.roam。Vue抛出了以下错误:

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: "value"

大致意思是:避免直接改变属性,因为当父组件重新呈现时,该值将被覆盖。相反,使用基于属性值的数据或计算属性。

这应该是我在子组件中,直接把v-model 指向了 value。所以做了修改,观察是否生效:

<template>
    <el-select :style="style" @change="returnBack" v-model="value" multiple placeholder="请选择">
        <el-option
                v-for="item in options"
                :key="item"
                :label="item"
                :value="item">
        </el-option>
    </el-select>
</template>

<script>
    export default {
        name: "TmRoam",
        props:{
            value:{
                type:Array
            },
            multiple:{
                type:Boolean,
                default:false
            },
            limit:{
                type:Number,
                default: 1,
            }
        },
        model:{
            prop:'value',
            event:'returnBack'
        },
        data() {
            return {
                options:['转让','出租', '转包', '合作', '入股', '互换', '招拍挂'],
            }
        },
        computed:{
            style(){
                if(this.multiple){
                    return 'min-width: 380px'
                }
            }
        },
        created() {

        },
        methods: {
            returnBack(){
                this.$emit('returnBack',this.value );
            }
        }
    }
</script>

<style>

</style>


从上图看出,已生效。原因是,父组件往子组件中的传值,只能读,不能写。如果需要更新父组件的值(v-model),则使用 this.$emit来触发。

{{tip}}