iOS自定义键盘滚动

579 阅读2分钟

业务涉及身份证号码输入,身份证号码格式固定,只允许输入数字和字面X。而在移动端上的键盘,输入数字只能使用数字键盘,输入字面只能使用字面键盘。用户体验不是很好,故自定义了一个键盘的实现。

如果输入框在页面底部时,此时进行输入,浏览器会将输入框往上移动,在实现自定义键盘时,也需要处理这种场景。一开始的想法是:

使用Dom的 getBoundingClientRect及时身份证输入框的 bottom, 然后通过 clientHeight(窗口可视大小) - keyboardHeight(键盘高度) 和输入框的 bottom 比较,如果

clientHeight - keyboardHeight < bottom

说明身份证输入框需要会被键盘遮住。此时需要向上滚动页面,避免出现被遮情况。 这种实现方式本正常情况下面没有问题,但在iOS上面会有一个场景就有问题:

先使用原生键盘输入姓名时,然后再点击输入身份证,会出现键盘遮挡身份证输入框的情况,而且稳定复现。

绞尽脑汁想不明白为什么会出现问题,还是得通过vConsole + 代码打日志形式定位问题。经过一番操作发现iOS上出现原生键盘时,可视窗口 clientHeight 的值不会变化,但是页面整体容器展示高度会被缩小,页面整体上移,导致通过getBoundingClientRect计算出来的 bottom 值会变小,从而影响最终的计算结果。

知道原因之后,有个最简单的解决方案, 使用万能的 setTimeout

setTimeout(xxx, 50)

实测 50ms 足够,如果不行就 100ms,稳够。


作为一个有追求的打工人,这种hack方式实在比较难以接受,还得继续尝试新的解决思路。上面是使用getBoundingClientRect计算身份证输入框距离可视窗口顶部的高度,那换一个思路,如果使用输入框相对高度和滚动距离来计算距离可视窗口顶部的高度是不是就不会没有页面偏移导致的问题了,事实证明确实是这样的:

  1. 计算身份证这个输入框的 offsetTop
  2. 计算当前页面滚动的距离 document.body.scrollTop
  3. 计算当前身份证输入框距离顶部的可视窗口顶部 offsetTop - scrollTop
  4. 计算键盘是否会遮挡住输入框 clientHeight - keyboardHeight < offsetTop - scrollTop + inputHeight(输入框的高度)
  5. 如果遮挡住就将body滚动一小段距离

总结一下:

还是踩了一个getBoundingClientRect的坑,移动页面可视窗口会受原生键盘的影响,在iOS系统,如果弹出原生键盘会导致可视窗口变化。