我正在参加「掘金·启航计划」
什么是v-model
在官网的第一个组件、我就们就看到v-model使用,实现了在表单输入元素或组件上创建双向绑定。
回忆一下 v-model 在原生元素上的用法:
<input v-model="value"></input>
上面的代码等价于:
<input :value="value" @input="value=$event.target.value"
所以v-model的原理:
v-bind绑定一个数据value- 监听元素的
input事件,更新value
原理搞清楚了,那么如何在自定义组件中实现v-model指令?
自定义组件实现v-model
这里,我们一起来实现一个电话号码输入组件来实现这个机制。
电话号码的规则:区号-电话号码(021-56789999)
组件的UI如下图:
可以看出,这个组件,有两个输入框,所以无法直接使用v-model指令来实现,需要我们自己实现v-model。
先给出组件的使用demo:
<TelephoneNumber v-model='value'></TelephoneNumber>
接下来、我们就来实现这个组件。
根据官方定义,在自定义组件上使用的时候是这样的:
<CustomInput
:modelValue="searchText"
@update:modelValue="newValue => searchText = newValue"
/>
也就是说,我们需要自己实现modelValue和update:modelValue的功能。
直接上代码:采用vue3实现的
<template>
<div class="phone-number">
<input style="width: 60px" v-model="state.area" @input="handleInput"></input>
<span style="width: 40px; text-align: center">{{ '-' }}</span>
<input style="flex: 1" v-model="state.value" @input="handleInput"></input>
</div>
</template>
<script setup>
import { reactive, watch } from 'vue'
const emit = defineEmits(['update:modelValue'])
const props = defineProps({
modelValue: {
type: String,
default: ''
}
})
const state = reactive({
area: props.modelValue.split('-')[0],
value: props.modelValue.split('-')[1]
})
watch(
() => props.modelValue,
() => {
;(state.area = props.modelValue.split('-')[0]), (state.value = props.modelValue.split('-')[1])
}
)
// 实现v-model的核心代码,触发update:modelValue事件
const handleInput = () => {
emit('update:modelValue', (state.area || '') + '-' + (state.value || ''))
}
</script>
<style lang="scss" scoped>
.phone-number {
width: 100%;
display: flex;
}
</style>
代码还是很简单的,主要就是组件内部实现,对v-model的值的处理,已经数据更新后,如何通知到v-model。
总结
这里还是总结一下吧。v-model的原理:
v-bind绑定一个数据value- 监听元素的
input事件,更新value