【博客大赛】+移动端4位/6位验证码/密码输入框H5实现
阶段一、六位验证码输入框
先贴图,需要实现的效果是这样的。
实现思路有两个:
1、用6个input,输入一个数字后将focus给下一个输入框。
2、用一个input和6个span,input隐藏,用span显示。
现在大部分都是使用的第二种方法。
两种方案遇到的坑,以及优缺点,如下:
方案一:6个input。
主要就是用js切换focus,在安卓是相当流畅的,但是在ios会严重卡顿,简直逼死强迫症。
HTML:
JS:
function inputNext (id){ // 传过来的id是个对象 var index = Number(id.id.split("_")[1]) if (id.value.length < 1) { // 删除 id.value = '' if (index > 1) { var preId = 'check_' + Number(Number(index) - 1) document.getElementById(preId).focus() return false } } else { if(id.value.length>1) { var nextValue = id.value.slice(1, 2) var nextId = 'check_' + Number(Number(index) + 1) id.value = id.value.slice(0, 1) if ((index+1) <= 6) { document.getElementById(nextId).value = nextValue document.getElementById(nextId).focus() } } } }
PS:我这里写的删除方法是有问题的,这也是我果断放弃这种方案的原因之一。
如果正常输入,然后删除是可以的。
但是输入几个数后,先点击中间的框删除一个数字,再回到最后,便只能将中间到最后的这几个删掉,最前面的还需要手动点一下得到focus才能删除。
这对用户来说,简直太不友好了。。。
CSS:
.divYZM{ width: 90%; margin: 0 auto; height: 100px; background-color: rgba(74, 35, 35, 0.42); } .numDiv{ display: block; width: 10%; float: left; border-radius: 5px; text-align: center; line-height: 60px; font-size: 20px; font-weight: 900; color: red; background-color: white; height: 60px; border: 0; padding: 0; margin: 0; margin-left: 5.7%; top: 20px; position: relative; caret-color: transparent; }
这里遇到的坑,举一个栗子。
input限制长度的属性maxlength
a、与如下两种配合使用(tel也可以限制)
或者
b、当type为number时不起作用。这时需要用js控制。
注意:此外,tel类型的input在ios上会调出全数字键盘,而number类型的input则会调出带有标点符号的键盘。
方案二:1个input和6个span。
隐藏input,用span显示内容。大坑就是,何种情况下能调起ios的软键盘呢?
先贴一下我刚开始的input样式。
width: 0; height :0; border: 0; padding: 0; margin: 0; 第二种 display:none;
简单粗暴,结果就是,ios木得反应。为啥呢,我想不通。
后来在晚上睡觉的时候我在想,我这两种方式input都么有占位啊,那是不是占位了就可以了呢?
经测果然是可以的(默默谴责自己懒了一下,没有将不隐藏input的情况,在手机上进行测试)。
但是这里要注意一点,input占位建议写成宽度占位,如果是高度占位,width为0时,会出现输入1234,显示为4321这种情况,光标默认在最前,且用js手动挪动光标到最后也是不起效果的。例如,类似代码我设置了宽度为0,且使用了如下方法挪动光标到最后,以解决输入1234,显示4321的问题。完全没得作用。后来突然想到是不是因为宽度为0。给input加了宽度才正常显示了。
错误代码示例:宽度为0
input的样式: #yzm{ width: 0; border: 0; padding: 0; margin: 0; height: .44rem; position: absolute; outline: none; color: transparent; text-shadow: 0 0 0 transparent; margin-left: -100%; } 对应的挪动光标的方法: let tObj = document.getElementById("#yzm"); let len = tObj.value.length; if(tObj.setSelectionRange){ tObj.setSelectionRange(len, len); tObj.focus(); }else if(tObj.createTextRange){ var rng = tObj.createTextRange(); rng.move('character', len); rng.select(); }
接下来贴正确代码。
CSS:
#yzm{ width: 90%; height: .44rem; border: 0; padding: 0; margin: 0; margin-left: -100%; outline: none; color: transparent; text-shadow: 0 0 0 transparent; position: absolute; } #yzmTable { width: 90%; height: 100px; margin: 0 auto; background-color: rgb(44 12 12 / 93%); border-radius: 5px; } #yzmTable span { display: block; width: 10%; height: 60px; float: left; border-radius: 5px; text-align: center; line-height: 60px; font-size: 20px; font-weight: 900; color: red; background-color: white; margin-left: 5.7%; top: 20px; position: relative; }
这里对input的样式也包括对光标的隐藏,我在第一种方案中对光标未进行处理,因为在看到ios的卡卡卡之后果断放弃了第一种方案。
HTML:
JS:
function intoYzm(index) { var ele = document.getElementById("yzm") ele.focus() } function yzmInsert() { // input内容改变时触发 for (var i = 1; i <= 6; i++) { var nextId = 's_' + i document.getElementById(nextId).innerHTML = ' ' } var yzm = document.getElementById("yzm").value var yzmArr = yzm.split(''); for (var i = 0; i < yzmArr.length; i++) { const num = yzmArr[i]; var id = 's_' + Number(i + 1) document.getElementById(id).innerHTML = ' ' + num + ' ' } } // 收起软键盘的方法,点击除了输入框之外的其他区域就收起软键盘 $('body').on('touchend', function(el) { if(el.target.tagName != 'SPAN') { $('yzm').blur() } })
在第二种方案中有两个地方注意下:
a、在js方法中加了对全局中6个span标签(即六个输入框)之外区域点击事件的监听,用以收起软键盘,方法如下。
$('body').on('touchend', function(el) { if(el.target.tagName != 'SPAN') { $('yzm').blur() } })
(比较粗糙,如果页面中还有别的部分就比较受影响了,可以自行改进)
b、在隐藏的input中添加了onclick方法,如下并且在其中用了blur方法使得此输入框失去焦点。为什么这么做呢?
因为此处的隐藏并非真正的隐藏,而是透明化处理,边框包括光标全部透明化,但实际上它还是占位的,所以当你点击输入框上方空白处时,仍会唤起软键盘,就和我们之前所想的点击输入框之外区域就收起软键盘冲突了。
因此将input自身的点击获取focus禁止掉,就OK了。
阶段二、四位验证码输入框
pia效果图
基本上是基于以上 阶段一、六位验证码输入方式(以下统称“阶段一”) 的后期填坑
这是仿照“阶段一”又新写了个验证码的小页面,有些微的不同
输入编号后四位,可能有X字母,所以隐藏input的type不能设置为number了,懒惰的我直接删掉了type属性(造坑开始)
且因为上次研究时漏掉了一些知识点,也造了一波坑,以下一一列举。
问题1、四位空格输入,1234,但是每次输入下一个数字,前面的内容都会整体向后移动,输完结果是4321;且输入一半点删除没反应。还得输入总共五位数字才能删除
??!我懵了,input给显示的几个span的赋值方式(见“阶段一”的js代码)是一样样的呀,怎么回事
debug发现隐藏的input值就已经是4321了,所以不是赋值方法的问题,以下是有问题的隐藏input的样式:
#IdentifyNoCheckInput { width: 0; border: 0; padding: 0; margin: 0; height: 10px; position: absolute; top: -11px; outline: none; color: transparent; text-shadow: 0 0 0 transparent; }
最初怀疑是光标自动到了最前面导致的,使用了百度的手动移动光标方法,并不管用。
对比“阶段一”中隐藏input的样式,可以发现本次宽度设成了0,有高度(高度随意,只要不挡住别的元素显示就行),有宽度或高度是为了占位,能唤起软键盘。
而“阶段一”中是有宽度的,这个差别引起了我的怀疑。为以上样式新增两条
width: 100%; margin-left: -100%;
再进行输入,正常了,输入1234就显示1234,也不会有删不掉的情况存在了。
第一个坑填坑完毕。
总结:设置宽度高度是为了占位,从而唤起软键盘。有高度或有宽度就可以,但是建议设置宽度,以免发生输入内容反转的情况。
问题2、部分ios手机无法正常唤起软键盘
在测试的时候,手机型号就那几个,大家测得顺顺当当。上线之后就报了好多ios无法正常输入的问题。
问题版本如下:
苹果p8,苹果6+(系统版本10),苹果6pok(系统版本11.4.1)和苹果6p plus(系统版本12.4.8)
以下是隐藏input的代码:
最初思路跑偏,开始各种查版本兼容的方法,但是没有合适的解决方案。
后在老大的提醒下,既然上篇文章中的验证码没有报这个问题,这个也不应该有问题啊。
对比发现就是少了个type,就想到是不是缺少type导致的,加了个type=”text”
emmmm,问题解决。
菜鸟教程描述如下:
大部分的坑都是自己给自己造的~~~
以下贴完整代码(我这个页面是以iframe被其他页面调用的,所以有个获取链接的操作以及拆分参数的方法)
请输入验证内容 --> 确认 4) { // 当type="number",属性maxlength不起作用 inNo = inNo.slice(0, 4) document.getElementById("IdentifyNoCheckInput").value = inNo } var inNoArr = inNo.split(''); for (var i = 0; i