🎉【实战】Vue3使用v-model自定义电话号码输入组件

1,088 阅读1分钟

我正在参加「掘金·启航计划」

什么是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如下图:

WX20230506-164442@2x.png

可以看出,这个组件,有两个输入框,所以无法直接使用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