订单页的金额输入框写了 type=number,测试提了个 bug:输入 12e3 提交后变成 12000,输入 1,200 直接成空值。前端还纳闷,明明加了必填属性。
number 类型只适合纯数字、不需要格式化的场景。它允许 e、E、正负号和小数点,内容非法时 value 返回空字符串,validity.badInput 才是 true,Number(value) 拿到的是 NaN。
金额和手机号别用 number
金额建议 type=text 配 inputmode=decimal,提交前自己 parse,固定两位小数。手机号、验证码用 type=text 加 inputmode=numeric,既避免前导 0 被吃掉,也避免移动端弹出带加减号的键盘。验证码再加 autocomplete=one-time-code,iOS 和安卓能直接读短信填充。
中文输入法会把值写脏
用户打拼音时 input 事件一直在触发,值里是 n i h a o 这样的字母串。监听 compositionstart 和 compositionend,组合期间跳过校验,结束再取一次值。搜索框做实时联想时这个问题最明显,不处理就会出现拼音字母被当成关键词提交。
校验交给浏览器,但别只靠它
required、pattern、minlength、maxlength、min、max、step 都能用,样式配合 :invalid 和 :valid。要自定义提示就 setCustomValidity,注意每次输入后要清空,否则会一直红着。form.reportValidity() 能主动弹出提示气泡。前端校验只是体验,服务端必须再验一遍。
几个容易踩的属性
- placeholder 不是标签:输入后提示就没了,配 label for 才可访问
- file 的 accept:只是过滤选择框,改后缀照样能传,类型得在后端判
- autocomplete:登录框写 username 和 current-password,别让浏览器填错位置
- disabled 与 readonly:前者不提交也不可聚焦,只想锁值就用 readonly
写法大概是这样:<input type='text' inputmode='decimal' pattern='[0-9]+([.][0-9]{1,2})?' required>。pattern 按整串匹配,不用加锚点,也别写反斜杠转义。
输入框的坑多半来自「以为类型能管住数据」。类型只影响键盘和基础校验,真正的边界还是得在提交那一刻算清楚。