v-model语法糖

1,446 阅读1分钟

v-model常用于表单元素上进行数据的双向绑定,比如input、textarea、select等组件。除了原生元素,它还能再自定义组件中使用,比如弹框的显示与隐藏。

我们都知道,v-model实际上是一个语法糖,可以拆解为两部分,props: value和events: input。

注:v-model为不同的输入元素使用不同的属性并抛出不同的事件:input和textarea元素使用value属性和input属性,checkbox和radio元素使用checked属性和change属性 ,select元素使用value属性和input属性 。

就是说组件必须提供一个名为value的prop和一个名为input 的自定义事件,满足这两个条件,开发人员就能在自定义组件上使用v-model。比如下面的示例,实现了一个数字加减器。

<template>
    <div>
        <button @click="increase(-1)">减1</button>
        <span style="color: brown; padding: 10px">{{currentValue}}</span>
        <button @click="increase(1)">加1</button>
    </div>
</template>

<script>
export default {
    name: 'test',
    props: {
        value: {
            type: Number
        }
    },
    data() {
        return {
            currentValue: this.value
        }
    },
    watch: {
        value(val) {
            this.currentValue = val;
        }
    },
    methods: {
        increase(val) {
            this.currentValue += val;
            this.$emit('input', this.currentValue);
        }
    }
}
</script>

props一般是不能在组件内修改,它是通过父组件修改,因此实现v-model一般都会有一个currentValue的内部data,初始时从props中的value获取一次值,当value修改,也会通过watch监听到并及时更新。组件内并不会修改value值,而是修改currentValue,同时将修改的值通过自定义事件input派发给父组件,父组件接收后,由父组件修改value的值。

<template>
    <div>
        <h3>This is a test demo</h3>
        <TestModel :value="value" @input="handleChange"></TestModel>
    </div>
</template>

<script>
import TestModel from './components/TestModel.vue'

export default {
    name: 'App',
    data () {
        return {
            value: 3
        }
    },
    methods: {
        handleChange(val) {
            this.value = val;
        }
    },
    components: {
        TestModel
    },
}
</script>

简单化,父组件可以直接用v-model:

<template>  
    <div>
        <h3>This is a test demo</h3>
        <TestModel v-model="value"></TestModel>
    </div>
</template>

<script>
import TestModel from './components/TestModel.vue'

export default {  
    name: 'App',  
    components: {    
        TestModel  
    },  
    data () {
        return {
            value: 3
        }
    }
}
</script>

如果你不想用value和input这两个名字,从Vue 2.2.0版本开始,提供了一个model的选项,可以指定他们的名字。所以数字加减器也可以这样写:

<template>
    <div>
        <button @click="increase(-1)">减1</button>
        <span style="color: brown; padding: 10px">{{currentValue}}</span>
        <button @click="increase(1)">加1</button>
    </div>
</template>

<script>
export default {
    name: 'test',
    props: {
        digit: {
            type: Number
        }    
    }, 
    model: {
        prop: 'digit',
        event: 'change'
    },
    data() {
        return {
            currentValue: this.digit
        } 
    },
    watch: {
        digit(val) {
            this.currentValue = val;
        }
    },
    methods: {
        increase(val) {
            this.currentValue += val; 
            this.$emit('change', this.currentValue);
        }
    }
}
</script>

完结啦~