Vue---父子组件双向数据绑定(Vue .sync与v-model)

使用场景:

       vue的prop是单向下行绑定:父级prop的更新会带动子组件更新,但是反过来不行,如果需要更新父级数据变化,一般是子组件通过 $emit 发射自定义事件方法,父组件进行监听这个事件方法,从而实现更新数据。
       有些情况,我们需要对prop进行“双向绑定”,例如,封装了一个单选radio子组件,父组件传过来初始绑定的值,在radio值发生变化时,此时父组件绑定的值并未发生更新。为了在radio值发生变化时,父组件可以同时更新,这时可以用 .sync 或v-model解决这个问题。

.sync方式

      formRadio子组件:

<template>
    <div class="elradio">
        <el-radio 
            :disabled="disabled"
            v-for="(item,index) in options"
            :key="index"
            v-model="val" 
            :label="item[showKey.value]"
            @change="change">
            {
   
   { item[showKey.label] }}
        </el-radio>
    </div>
</template>
<script>
export default {
    name : 'formRadio',
    props : {
        value : {
            type : String | Number,   //父组件传过来绑定(v-model)的值
            default(){
                return '';
            }
        },
        showKey : {                   //展示数据对象对应label和value对应的key值
            type : Object,
            default(){
                return {
                    label : 'label',
                    value : 'value'
                }
            }
        },
        parentOptions : {              //父组件传过来的options枚举值
            type : Array,
            default(){
                return []
            }
        },
        dataType : {
            type : String,             //父组件没有传枚举值,可以通过dataType使用自定义的一些枚举值
            default(){
                return ''
            }
        },
        disabled : {                    //是否禁用
            type : Boolean,
            default(){
                return false;
            }
        },
    },
    data(){
        return {
            val : '',       //单选按钮绑定的值
            options : [],   //单选按钮要展示的枚举值
            sexType : [
                {
                    value: '1',
                    label: '男'
                }, 
                {
                    value: '2',
                    label: '女'
                }, 
            ]
        }
    },
    mounted(){
        if (this.parentOptions) {           //父组件传枚举值,就展示父组件的
            this.options = this.parentOptions;
        }
        if (this.dataType) {                //父组件没传枚举值,通过传dataType使用内部自定义的枚举值
            this.options = this[this.dataType]
        }
        if(this.value){                     //初始化单选按钮绑定的值
            this.val = this.value;
        }
    },
    methods : {
        change(currentRadioVal){                 //值发生变化后,同时更新父组件绑定的值
            this.$emit('update:value', currentRadioVal);   //更新父组件初始化传过来绑定的值(.sync方式传值时)
        }
    }
}
</script>
<style scoped>
.elradio{
    text-align: left;
    width: 100%;
}
</style>

父组件:

<formRadio  :value.sync='forma.sex' :dataType="'sexType'"></formRadio>

v-model方式

      父子组件同时使用v-model指令,父组件v-model绑定的值会传给子组件v-model绑定的props中的值。即代替了之前 :value.sync 方式传值,直接使用v-model传值。此时,子组件唯一不同的地方是更新父组件值的方式发生了变化。

formRadio子组件:

<template>
    <div class="elradio">
        <el-radio 
            :disabled="disabled"
            v-for="(item,index) in options"
            :key="index"
            v-model="val" 
            :label="item[showKey.value]"
            @change="change">
            {
   
   { item[showKey.label] }}
        </el-radio>
    </div>
</template>
<script>
export default {
    name : 'formRadio',
    props : {
        value : {
            type : String | Number,   //父组件传过来绑定(v-model)的值
            default(){
                return '';
            }
        },
        showKey : {                   //展示数据对象对应label和value对应的key值
            type : Object,
            default(){
                return {
                    label : 'label',
                    value : 'value'
                }
            }
        },
        parentOptions : {              //父组件传过来的options枚举值
            type : Array,
            default(){
                return []
            }
        },
        dataType : {
            type : String,             //父组件没有传枚举值,可以通过dataType使用自定义的一些枚举值
            default(){
                return ''
            }
        },
        disabled : {                    //是否禁用
            type : Boolean,
            default(){
                return false;
            }
        },
    },
    data(){
        return {
            val : '',       //单选按钮绑定的值
            options : [],   //单选按钮要展示的枚举值
            sexType : [     //自定义的枚举值
                {
                    value: '1',
                    label: '男'
                }, 
                {
                    value: '2',
                    label: '女'
                }, 
            ]
        }
    },
    mounted(){
        if (this.parentOptions) {           //父组件传枚举值,就展示父组件的
            this.options = this.parentOptions;
        }
        if (this.dataType) {                //父组件没传枚举值,通过传dataType使用内部自定义的枚举值
            this.options = this[this.dataType]
        }
        if(this.value){                     //初始化单选按钮绑定的值
            this.val = this.value;
        }
    },
    methods : {
        change(currentRadioVal){                 //值发生变化后,同时更新父组件绑定的值
            //this.$emit('update:value', currentRadioVal);   //更新父组件初始化传过来绑定的值(.sync方式传值时)
            this.$emit('input', currentRadioVal);   //更新父组件初始化传过来绑定的值(v-model方式传值时)
        }
    }
}
</script>
<style scoped>
.elradio{
    text-align: left;
    width: 100%;
}
</style>

父组件:此时,父组件的传值方式变为了v-model传值方式。

<formRadio  v-model='forma.sex' :dataType="'sexType'"></formRadio>

猜你喜欢

转载自blog.csdn.net/qq_39115469/article/details/110661030