用过vuejs的前端工程师,对于v-model一定印象深刻。它向类似textarea,input等原生html原生添加双向数据绑定的能力非常方便。但是对于你的定制vue组件并不是能够直接应用v-model的,我们需要做一些额外的工作,但是这个额外工作是非常简单的。
为了理解如何给你的组件提供v-momeiydel支持,你应该深入地了解v-model本身底层是如何工作地。v-model初看起来就像是一个魔术,但是真的没有那么神秘。
v-model="syncedProp"
等价于以下代码
:value="syncedProp" @input="syncedProp=$arguments[0] 或者
:value="syncedProp" @input="syncedProp=$event.target.value
理解了以上地两点,那么如果需要支持v-model,你自己的组件需要做的就是:
1. 接收一个:value的property
2. 当用户变更value值的时候发送一个@input事件
基础实现:
我们假设我们有一个date picker的组件,该组件接收year,month的value:{month:1,year:2019},我们希望该组件有两个输入Inputs,一个用于month,一个用于year,并且通过v-model来更新绑定的对象.这里是实现的例子代码:
<template> <div class="date-picker"> Month: <input type="number" ref="monthPicker" :value="value.month" @input="updateDate()"/> Year: <input type="number" ref="yearPicker" :value="value.year" @input="updateDate()"/> </div> </template> <script> export default { props: ['value'], methods: { updateDate() { this.$emit('input', { month: +this.$refs.monthPicker.value, year: +this.$refs.yearPicker.value }) } } }; </script>
有了以上的实现代码后,我们就可以像下面的代码来使用它:
<template> <div class="wrapper"> <date-picker v-model="date"></date-picker> <p> Month: {{date.month}} Year: {{date.year}} </p> </div> </template> <script> import DatePicker from './DatePicker.vue'; export default { components: { DatePicker }, data() { return { date: { month: 1, year: 2017 } } } }) </script>
总结以上范例代码,我们可以看到就做了两件事:
1. 接受一个value这个prop,并通过该value prop传入的值在本组件中使用
2. 当需要通知外部数据已经变化需要更新外部的绑定数据时,只需要emit一个input事件即可!
高级一点的例子
在上面基础版本基础上,我们把事情搞得稍微复杂一点,比如,我们传入的日期格式不是object形式,而时字符串形式mm/yyyy的格式,这时需要使用的化,必须要做进一步处理,同样地,当用户主动修改了数据修正外部地数据时,也需要再组合成一个字符串emit出去!
<template> <div class="date-picker"> Month: <input type="number" ref="monthPicker" :value="splitDate.month" @input="updateDate()"/> Year: <input type="number" ref="yearPicker" :value="splitDate.year" @input="updateDate()"/> </div> </template> <script> export default { props: ['value'], computed: { splitDate() { const splitValueString = this.value.split('/'); return { month: splitValueString[0], year: splitValueString[1] } } }, methods: { updateDate() { const monthValue = this.$refs.monthPicker.value; const yearValue = this.$refs.yearPicker.value; this.$emit('input', `${monthValue}/${yearValue}`); } } }; </script>
定制v-model所使用的prop和event
如上面所说,v-model匹配的就是value属性以及input的事件上报,但是我们也可以修改这个默认的行为。
其办法就是通过在我们的定制组件中,声明一个model对象,该model对象包含两个字段,一个prop,一个event分别用于对应的value和input事件
比如下面的组件代码:
export default { prop: ['cprop'], model: { prop: 'cprop', event: 'cevent' } methods: { handleInput (value) { this.$emit('cevent', value) } } }
如果我们在html中像下面来使用:
<basic-input v-model="email" /> <!-- 等价于以下代码 --> <basic-input :cprop="email" @cevent="e => email = e.target.value" />