东林博客

Vue自定义组件的v-model剖析

在Vue中,v-model是唯一支持双向绑定的指令。用于表单控件绑定,但不代表只能用于表单控件绑定。在创建自定义组件中使用v-model,并没有什么神秘的,是使用了如下的语法糖。

父组件

<template>
<area-selector v-model="region"></area-selector>
</template>
<script>
import AreaSelector from '../components/area-selector.vue'
export default{
    data(){
        return {
        }
    }
}

子组件 area-selector

<template>
    <div class="row">
        <el-select class="col-sm-3" @change="onChangeProvince" v-model="province_id" placeholder="请选择">
            <el-option
                    v-for="item in provinces"
                    :key="item.id"
                    :label="item.name"
                    :value="item.id">
            </el-option>
        </el-select>
        <el-select class="col-sm-3" @change="onChangeCity" v-model="city_id" placeholder="请选择">
            <el-option
                    v-for="item in cities"
                    :key="item.id"
                    :label="item.name"
                    :value="item.id">
            </el-option>
        </el-select>
        <el-select class="col-sm-3" v-model="district_id" placeholder="请选择">
            <el-option
                    v-for="item in districts"
                    :key="item.id"
                    :label="item.name"
                    :value="item.id">
            </el-option>
        </el-select>
    </div>
</template>

<script>
    export default {
        name: "AreaSelector",
        props:['value'],
        data() {
            return {
                province_id:'',
                city_id:'',
                district_id:'',
                provinces:[],
                cities:[],
                districts:[]
            }
        },
        watch:{
            province_id(){
                this.getCities()
                this.updateArea()
            },
            city_id(){
                this.getDistricts()
                this.updateArea()
            },
            district_id(){
                this.updateArea()
            }
        },
        created() {
            this.getProvinces()
        },
        methods: {
            updateArea(){
                this.$emit('input', [this.province_id,this.city_id,this.district_id])
            },
            getProvinces(){
                this.$axios.get('/admin/areas',{parent_id:1}).then((res)=>{
                    if(res.status == 200){
                        this.provinces = res.data;
                    }else{
                        this.$message.warning('获取地区信息失败')
                    }
                })
            },
            getCities(){
                this.$axios.get('/admin/areas',{parent_id:this.province_id}).then((res)=>{
                    if(res.status == 200){
                        this.cities = res.data;
                    }else{
                        this.$message.warning('获取地区信息失败')
                    }
                })
            },
            getDistricts(){
                this.$axios.get('/admin/areas',{parent_id:this.city_id}).then((res)=>{
                    if(res.status == 200){
                        this.districts = res.data;
                    }else{
                        this.$message.warning('获取地区信息失败')
                    }
                })
            },
            onChangeProvince(){
                this.city_id = this.district_id = ''
            },
            onChangeCity(){
                this.district_id = ''
            }
        }
    }
</script>

<style>

</style>

这个语法糖的原理是:在组件中声明一个name为value的props,并且通过触发input事件传入一个值,就能修改这个value。

{{tip}}