这一个小需求,断断续续解决了好久,中间一直存在各种bug,现在基本上已经完全解决,因此,打算从头到尾记录一下,方便以后查询。
需求
开始的时候,还是把需求简单的说下:
移动端中,弹出系统的数字键盘,实现344分割手机号
需求明确之后,下面就是分析需求,然后才能确定实现方式:
- 明确说明是移动端,那么也就是说,兼容问题不需要考虑太多
- 如果要弹出系统的数字键盘,那么符合条件的只有一种,那就是
type="phone"
的input输入框 - 在输入的时候,实现344分割手机号,这个时候就要监视输入框中内容的变化,这个可以结合Vue的
watch
来实现 - 手机号344分割,那么输入框中输入的最大长度应该就是13了
经过分析可以看出,实际需要使用的知识点并不是很多。分析完成之后,下面就要来具体实现这个需求了。
实现
搭建结构
首先,在写真正的程序之前,要把结构搭建完成,后续写代码直接在结构中写就可以了。
- 首先来搭建html5的代码结构,然后自定义input的样式(方便后续查看)
- 定义input输入框,并设置
type
和maxlength
- 通过
v-model
实现数据的双向绑定 - 引入vue.js并搭建基本的代码结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style type="text/css">
/* 自定义input输入框的样式 */
#app input { width: 100%; height: 50px; border: 1px solid red; font-size: 30px; outline: none; }
</style>
</head>
<body>
<div id="app">
<!-- 设置type和maxlength,并实现数据双向绑定 -->
<input v-model="phone" type="phone" placeholder="请输入手机号" maxlength="13">
</div>
</body>
</html>
<script type="text/javascript" src="./vue2.4.2.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data() {
return {
phone: ''
}
},
watch: {
phone(newValue, oldValue) {
// 具体的代码在这里实现
}
}
})
</script>
分析输入和输出
在具体实现之前,首先要明白,输入和输出的分别触发什么样的操作。
下面,我们把watch中的newValue
和oldValue
的值输出,看一下规律。
phone(newValue, oldValue) {
// 具体的代码在这里实现
console.group('< === 是否是输入 === >')
console.log("%c%s", "color:red", `${newValue.length > oldValue.length}`)
console.groupEnd('< === 是否是输入 === >')
}
当在输入框中输入内容的时候:
当在输入框中删除内容的时候:
从分析可以看出,在输入的时候,长度是增加的,删除的时候,长度是减少的。
删除的具体实现
在删除的时候,会出现两个转折点,就是在删除第10个元素或者第5个元素的时候,要自动删除空格。
很明显,这里出现了两个条件,下标为4的时候和下标为9的时候,要去除字符串的空格。
phone(newValue, oldValue) {
// 具体的代码在这里实现
if (newValue.length > oldValue.length) {
// ...
} else {
if (newValue.length === 9 || newValue.length === 4) {
this.phone = this.phone.trim()
}
}
}
代码写出了之后,看着有些不舒服,有没有优化方案呢?
再次经过分析会发现,既然在下标为4或9的时候,我们做的事是去除空格,那么就可以根据去空格的特性(有空格去除空格,无空格不进行处理),直接只做去除空格的操作,不进行判断了。
phone(newValue, oldValue) {
// 具体的代码在这里实现
if (newValue.length > oldValue.length) {
// ...
} else {
this.phone = this.phone.trim()
}
}
现在,删除的功能实现了,并且代码也进行了优化,下面开始实现输入的操作。
输入的具体实现
下面来分析一下输入的问题:
在输入的时候,当值的长度小于3的时候,肯定是原样返回的;当值的长度大于等于3且小于7的时候,要增加一个空格;当长度大于等于7的时候,要增加两个空格。这个时候就要牵涉到条件判断了。
另外,在判断值的时候,肯定是判断总数字的个数,因此是去除空格的。
phone(newValue, oldValue) {
// 具体的代码在这里实现
if (newValue.length > oldValue.length) {
if (newValue.replace(/\s/g, '').length < 3) {
this.phone = newValue.replace(/\s/g, '')
} else if (newValue.replace(/\s/g, '').length >= 3 && newValue.replace(/\s/g, '').length < 7) {
this.phone = newValue.replace(/\s/g, '').replace(/(\d{3})/, '$1 ')
} else if (newValue.replace(/\s/g, '').length >= 7) {
this.phone = newValue.replace(/\s/g, '').replace(/(\d{3})(\d{4})/, '$1 $2 ')
}
} else {
this.phone = this.phone.trim()
}
}
我的天哪,这个代码怎么看着那么乱,应该可以优化的。由于正则表达式是一个强大的工具,因此,可以结合正则来优化。
首先,我们可以把空格作为分割点,那么空格之前的内容属于一组,所以共分三组。第一组的长度为3个数字,第二组和第三组的长度都是0-4个数字,因此,通过正则可以简化代码:
phone(newValue, oldValue) {
// 具体的代码在这里实现
if (newValue.length > oldValue.length) {
this.phone = newValue.replace(/\s/g, '').replace(/(\d{3})(\d{0,4})(\d{0,4})/, '$1 $2 $3')
} else {
this.phone = this.phone.trim()
}
}
简化代码
上面的代码已经基本算精简了,可是,如果使用三目运算符,还可以更加精简:
phone(newValue, oldValue) {
// 具体的代码在这里实现
this.phone = newValue.length > oldValue.length ? newValue.replace(/\s/g, '').replace(/(\d{3})(\d{0,4})(\d{0,4})/, '$1 $2 $3') : this.phone.trim()
}
至此,该需求已经完成了,最后实际的代码只有一句。
总结
其实这个需求很简单,需要总结的东西不多,因此,在这里把具体的代码实现贴出来,方便后续使用:
<div id="app">
<!-- 设置type和maxlength,并实现数据双向绑定 -->
<input v-model="phone" type="phone" placeholder="请输入手机号" maxlength="13">
</div>
<script type="text/javascript" src="./vue2.4.2.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data() {
return {
phone: '' // 双向绑定的数据
}
},
watch: {
phone(newValue, oldValue) { // 监听
this.phone = newValue.length > oldValue.length ? newValue.replace(/\s/g, '').replace(/(\d{3})(\d{0,4})(\d{0,4})/, '$1 $2 $3') : this.phone.trim()
}
}
})
</script>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。