移动端 验证码/密码 输入框实现--安卓/ios适用

楼主

lanlan123 [离线]

0☆☆☆☆☆

发帖数:171 积分-1
1楼
实现思路有两个:



1、用6个input,输入一个数字后将focus给下一个输入框。

2、用一个input和6个span,input隐藏,用span显示。



现在大部分都是使用的第二种方法。(当然,如果你能说服产品也可以只用一个普通的input输入框,就什么都不用考虑了)



两种方案遇到的坑,以及优缺点,如下:



方案一:6个input。



主要就是用js切换focus,在安卓是相当流畅的,但是在ios会严重卡顿,简直逼死强迫症。



HTML:

<div class="divYZM">
  <!-- onpropertychange是为了避免在ios中oninput方法不被触发 -->
  <input id="check_1" class="numDiv" type="number" oninput="inputNext(check_1)" onpropertychange="inputNext(check_1)"/>
  <input id="check_2" class="numDiv" type="number" oninput="inputNext(check_2)" onpropertychange="inputNext(check_2)"/>
  <input id="check_3" class="numDiv" type="number" oninput="inputNext(check_3)" onpropertychange="inputNext(check_3)"/>
  <input id="check_4" class="numDiv" type="number" oninput="inputNext(check_4)" onpropertychange="inputNext(check_4)"/>
  <input id="check_5" class="numDiv" type="number" oninput="inputNext(check_5)" onpropertychange="inputNext(check_5)"/>
  <input id="check_6" class="numDiv" type="number" oninput="inputNext(check_6)" onpropertychange="inputNext(check_6)"/>
</div>
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也可以限制)

<input type="text"> 或者
<input type="password">


b、当type为number时不起作用。这时需要用js控制。

<input type="number" oninput="if(value.length>5) value=value.slice(0,5)" />
注意:此外,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的情况,在手机上进行测试)。



接下来贴正确代码。



CSS:

#yzm{
  width: 0;
  border: 0;
  padding: 0;
  margin: 0;
  height: .44rem;
  position: absolute;
  outline: none;
  color: transparent;
  text-shadow: 0 0 0 transparent;
  width: 300%;
  margin-left: -100%;
}
#yzmTable {
  width: 90%;
  margin: 0 auto;
  height: 100px;
  /* border: 1px solid red; */
  background-color: rgba(74, 35, 35, 0.42);
  /* opacity: 0.1; */
}
#yzmTable span {
  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;
  margin-left: 5.7%;
  top: 20px;
  position: relative;
}
这里对input的样式也包括对光标的隐藏,我在第一种方案中对光标未进行处理,因为在看到ios的卡卡卡之后果断放弃了第一种方案。



HTML:

<input id="yzm" type="tel" maxlength="6" value="" oninput="yzmInsert()">
<div id="yzmTable">
  <span id="s_1" onclick="intoYzm(1)">&nbsp;&nbsp;</span>
  <span id="s_2" onclick="intoYzm(2)">&nbsp;&nbsp;</span>
  <span id="s_3" onclick="intoYzm(3)">&nbsp;&nbsp;</span>
  <span id="s_4" onclick="intoYzm(4)">&nbsp;&nbsp;</span>
  <span id="s_5" onclick="intoYzm(5)">&nbsp;&nbsp;</span>
  <span id="s_6" onclick="intoYzm(6)">&nbsp;&nbsp;</span>
</div>
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 = ''&nbsp;&nbsp;''
  }
  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 = ''&nbsp;'' + num + ''&nbsp;''
  }
}

// 收起软键盘的方法,点击除了输入框之外的其他区域就收起软键盘
$(''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 id="yzm" type="tel" maxlength="6" value="" oninput="yzmInsert()" onclick="this.blur();">
因为此处的隐藏并非真正的隐藏,而是透明化处理,边框包括光标全部透明化,但实际上它还是占位的,所以当你点击输入框上方空白处时,仍会唤起软键盘,就和我们之前所想的点击输入框之外区域就收起软键盘冲突了。



因此将input自身的点击获取focus禁止掉,就OK了。



之前都是自己乱七八槽的瞎记,第一次写给别人看,经验不足,时间仓促。不足之处,还望指正。

蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、网站建设 、平面设计服务。

2019/7/23 9:32:45
返回本版
1

请您先 登录 再进行发帖

快速回复楼主