记网页文本框中的一些坑

记网页文本框中的一些坑

最近在在做需求的时候有碰到一个六位数密码输入框的需求,用户输入只能输入数字,不能输入其他字符,同时移动端要求唤起的是数字键盘。

很容易想到这样的实现:添加一个输入框,使其隐藏——width=0或者是opacity=0都可以,然后在其上覆盖一层label,和外面的展示的假输入框等大,这样用户点击label就能focus到输入框上。最后将输入框内的内容渲染到假输入框上,即能达到很好的效果。

function renderPasswordInput(){
    return (<div class={style.passContainer}>
        <label class={style.passHideInputLabel}>
            <input class={{
                    [style.passHideInput]: true,
                    [style.inputHideFix]: hideInput.value
                }}
                type="tel"
                ref="passInputElement"
                value={pass.value}
                onInput={passInputHandle}
                disabled={state.value === VERIFY_STATUS.PENDDING}
                autocomplete="off"/>
        </label>
        {showPass.value.map(i =>
            <span
                class={{
                    [style.passInput]: true,
                    [style.active]: i.length > 0,
                    [style.danger]: state.value === VERIFY_STATUS.FAIL
                }}
            >{i}</span>)}
    </div>);
}

实际实现使用了vue,实现过程中发现了一些输入框的问题,在此做一个记录。

问题一、Number类型的输入框没有有效小数位时获取不到小数点

type=number类型的输入框中的内容如果没有有效的小数位,例如内容为:123. 此时获取该输入框的value,会发现是没有这个小数点的。

Chrome中获取Number的value

而且此时将其value修改为”123”,编辑框中的实际内容并不会变化。

Chrome中修改value内容不变

但是在Firefox中,虽然获取到的value也不包含小数点,但是将其value修改为”123”,输入框的内容将会变成123。

Firefox中修改value内容发生变化

实际上,一开始我的做法是如果Number输入框中输入小数,则实际值会变成向下取整。后来发现如果刚输入小数点的时候由于value不包含小数,且在chrome中修改其value为整数并不改变实际输入框内容,这就导致:

  1. 输入小数点的时候,输入框内容为”123.”,对应到的变量value为123,渲染结果也为123
  2. 再输入一位,此时输入框内容变成”123.4”,对应到的变量value向下取整为123,渲染结果仍然为123
  3. 那么我在密码框中输入123.4,其中.的那一次输入是无效的,有效输入应该是1234,而在这种情况下,值变成了123,和需要表现不符

问题二、Number类型的输入框可以输入无效值

这个问题的根源在于有些符号确实在数字中使用,但是如果符号的位置不对,整个数字不合法,并且其value会变成一个空字符串。

在数字输入框中输入无效值,此时value为空字符串

和前面的情况不一样,在这里对value赋值空字符串,确实可以清除掉不合法的内容。

对value赋值可以清除不合法内容

但是对于vue框架来说就不是这样了,在使用vue框架的时候,并没有清除掉错误的内容,也就是说如果我开头的时候输入一个e,接下来无论输入什么都不会显示;或者在输入的过程中输入一个短横线,当前已经输入的内容会直接消失——这都是因为此时获取到的value为空字符串。

为什么会这样呢?个人推测这其实和vue的渲染方式有关。众所周知,vue生成的DOM其实并不是真实的DOM,实际上是一个虚拟DOM,在虚拟DOM发生变化之后,vue会对比实际DOM和虚拟DOM,然后高效地渲染内容。那么对于这里,由于该input元素在修改前后的value都为空字符串,自然没必要进行重渲染,也就不会清除掉无效的内容了。

问题三、iOS中隐藏输入框的问题

在iOS中,使用任何方式隐藏了输入框(已尝试:width: 0px,opacity: 0,left: -9999px),则输入框获取焦点的时候页面不会自动上滑。

当然这个问题解决起来也很简单,默认不隐藏,focus的时候再隐藏就好了,blur的时候要重新显示。

//在iOS上隐藏密码框会造成键盘弹起时页面不上移,因此等弹起之后再隐藏
//此处hideInput控制对应的class
function passFocusChangeHandle(){
    let inputElement = refs.passInputElement;
    if(inputElement === document.activeElement){
        setTimeout(() => { hideInput.value = true; }, 1);
    }
    else{
        setTimeout(() => { hideInput.value = false; }, 1);
    }
}

问题四、部分安卓手机上输入框宽度为0会导致输入反向

经过测试发现,在一些安卓手机上把输入框的宽度变成0会导致输入反向,即输入1、2、3,编辑框内容变成了321。

因此最后使用了opacity: 0而不是用width: 0的方式来隐藏输入框。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!