您的位置:首页 > 移动开发

移动端4位/6位验证码/密码输入框H5实现

2021-04-28 18:16 851 查看

阶段一、六位验证码输入框

先贴图,需要实现的效果是这样的。

实现思路有两个:

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



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: