【博客大赛】+移动端4位/6位验证码/密码输入框H5实现
阶段一、六位验证码输入框 先贴图,需要实现的效果是这样的。 实现思路有两个: 1、用6个input,输入一个数字后将focus给下一个输入框。 2、用一个input和6个span,input隐藏,用span显示。 现在大部分都是使用的第二种方法。 两种方案遇到的坑,以及优缺点,如下: 方案一:6个input。 主要就是用js切换focus,在安卓是相当流畅的,但是在ios会严重卡顿,简直逼死强迫症。 HTML: JS: functioninputNext(id){//传过来的id是个对象 varindex=Number(id.id.split("_")[1]) if(id.value.length<1){//删除 id.value='' if(index>1){ varpreId='check_'+Number(Number(index)-1) document.getElementById(preId).focus() returnfalse } }else{ if(id.value.length>1){ varnextValue=id.value.slice(1,2) varnextId='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:0auto; 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:000transparent; margin-left:-100%; } 对应的挪动光标的方法: lettObj=document.getElementById("#yzm"); letlen=tObj.value.length; if(tObj.setSelectionRange){ tObj.setSelectionRange(len,len); tObj.focus(); }elseif(tObj.createTextRange){ varrng=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:000transparent; position:absolute; } #yzmTable{ width:90%; height:100px; margin:0auto; background-color:rgb(441212/93%); border-radius:5px; } #yzmTablespan{ 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: functionintoYzm(index){ varele=document.getElementById("yzm") ele.focus() } functionyzmInsert(){//input内容改变时触发 for(vari=1;i<=6;i++){ varnextId='s_'+i document.getElementById(nextId).innerHTML='' } varyzm=document.getElementById("yzm").value varyzmArr=yzm.split(''); for(vari=0;i<yzmArr.length;i++){ constnum=yzmArr[i]; varid='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:000transparent; } 最初怀疑是光标自动到了最前面导致的,使用了百度的手动移动光标方法,并不管用。 对比“阶段一”中隐藏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 } varinNoArr=inNo.split(''); for(vari=0;i