Vue.js中如何通过v-model实现指定格式的电话号码输入
Vue.js 实现电话号码格式化输入(基于v-model场景)
要实现输入电话号码时自动显示为 (123) - 456 - 78 - 90 的格式,直接用原生v-model无法满足需求,因为它会直接同步原始输入值。我们可以通过拆解双向绑定逻辑,结合输入事件处理和格式化函数来实现,同时保持数据的双向同步。
方案一:组件内直接处理(适合单组件使用)
修改后完整代码
<template> <div v-for="(about, index) in abouts" :key="index"> <!-- 用:value绑定格式化后的显示值,手动处理输入事件 --> <input type="text" :value="formatPhone(about.phone)" @input="handlePhoneInput($event, index)" placeholder="请输入电话号码" > <input type="text" v-model="about.mail" placeholder="请输入邮箱"> </div> </template> <script> export default { data() { return { abouts: [{ phone: '', mail: '' }, { phone: '', mail: '' }] } }, methods: { // 把纯数字字符串格式化为指定样式 formatPhone(phone) { // 过滤所有非数字字符 const pureNum = phone.replace(/\D/g, '') let formatted = '' // 按规则拼接格式 if (pureNum.length > 0) { formatted += `(${pureNum.slice(0, 3)}` if (pureNum.length >= 3) formatted += ') - ' if (pureNum.length >= 4) formatted += pureNum.slice(3, 6) if (pureNum.length >= 6) formatted += ' - ' if (pureNum.length >= 7) formatted += pureNum.slice(6, 8) if (pureNum.length >= 8) formatted += ' - ' if (pureNum.length >= 9) formatted += pureNum.slice(8, 10) } // 限制最终显示长度,避免超出格式范围 return formatted.slice(0, 16) }, // 处理输入事件,同步数据源和显示内容 handlePhoneInput(event, index) { // 提取输入中的纯数字 const pureNum = event.target.value.replace(/\D/g, '') // 更新数据源(存储纯数字,方便后续使用) this.abouts[index].phone = pureNum // 把格式化后的内容赋值回输入框 event.target.value = this.formatPhone(pureNum) } } } </script>
逻辑说明
- 放弃直接使用
v-model,改用:value绑定格式化后的显示内容 handlePhoneInput方法负责:- 过滤输入中的非数字字符,只保留有效数字
- 将纯数字更新到数据源的
phone字段 - 把格式化后的字符串赋值回输入框,实现实时格式化显示
formatPhone方法负责将纯数字字符串按照(XXX) - XXX - XX - XX的规则拼接成目标格式
方案二:自定义指令(适合多处复用)
如果多个组件或页面都需要电话号码格式化,可以封装成自定义指令,提升代码复用性。
完整代码
<template> <div v-for="(about, index) in abouts" :key="index"> <input type="text" v-phone-format="about.phone" placeholder="请输入电话号码" > <input type="text" v-model="about.mail" placeholder="请输入邮箱"> </div> </template> <script> // 抽离格式化函数 function formatPhone(phone) { const pureNum = phone.replace(/\D/g, '') let formatted = '' if (pureNum.length > 0) { formatted += `(${pureNum.slice(0, 3)}` if (pureNum.length >= 3) formatted += ') - ' if (pureNum.length >= 4) formatted += pureNum.slice(3, 6) if (pureNum.length >= 6) formatted += ' - ' if (pureNum.length >= 7) formatted += pureNum.slice(6, 8) if (pureNum.length >= 8) formatted += ' - ' if (pureNum.length >= 9) formatted += pureNum.slice(8, 10) } return formatted.slice(0, 16) } export default { data() { return { abouts: [{ phone: '', mail: '' }, { phone: '', mail: '' }] } }, directives: { phoneFormat: { // 元素挂载时初始化格式化 mounted(el, binding) { el.value = formatPhone(binding.value) }, // 数据源更新时同步格式化显示 update(el, binding) { if (el.value !== formatPhone(binding.value)) { el.value = formatPhone(binding.value) } }, // 绑定输入事件处理逻辑 bind(el, binding, vnode) { el.addEventListener('input', () => { const pureNum = el.value.replace(/\D/g, '') // 更新数据源 vnode.context[binding.expression] = pureNum // 同步格式化显示 el.value = formatPhone(pureNum) }) } } } } </script>
使用说明
只需要在需要格式化的输入框上添加v-phone-format="数据源字段"即可,指令会自动处理输入格式化和数据同步。
注意事项
- 数据源中存储的是纯数字字符串,方便后续接口调用、存储等操作,显示层则是格式化后的样式
- 自动过滤非数字输入,避免用户输入特殊字符导致格式混乱
- 限制最大输入长度为10位数字,刚好匹配目标格式的位数
内容的提问来源于stack exchange,提问作者oguzcan
相关产品推荐
相关产品推荐

