input事件在中文输入法下仅在“上屏”时触发,需结合compositionstart/end监听并用blur兜底,防抖和校验须避开中间态,跨浏览器需兼顾input/change/blur三者。

input事件在中文输入法下只响应“上屏”,不是“按键”
用户打“北京”,拼音过程(b-e-i-j-i-n-g)不会触发input,只有按下空格或回车让“北京”真正写入value时,input才触发一次。这不是 bug,是浏览器对 Composition API 的标准实现——DOM 不更新,事件就不发。
常见错误现象:搜索框加了防抖,用户输到“上海”还没按空格就切走窗口,input根本没触发,防抖定时器没执行,请求永远发不出去。
- 必须监听
compositionstart和compositionend,前者标记进入输入法模式,后者才是真实值落定的时机 -
compositionupdate可选,用于获取当前拼音串(如“shangh”),但多数业务不需要 - 失焦(
blur)要做兜底:对比上次记录的value,有变化就强制执行校验或提交
change事件在移动端和 Safari 中可能根本不触发
change依赖“失焦 + 值变化”两个条件,而移动端软键盘收起不等于失焦,Safari(≤16.4)在type="date"或中文输入后也常漏掉change。你看到表单没校验、提交拿不到最新值,大概率是change压根没来。
使用场景判断:仅当明确需要“最终确认”时才用change,比如select选项切换、file选择完成、提交前统一校验。
立即学习“前端免费学习笔记(深入)”;
-
checkbox和radio仍该用change,因为它们没有“失焦才有变化”的语义 - 不要指望
change捕获实时输入,它对input和textarea天生延迟 - 若必须兼容旧 IE(已极少见),
change比input更稳,但现代项目基本不用考虑
React/Vue 中 onChange 实际等价于 input,不是原生 change
框架封装的onChange(如 React 的onChange、Vue 的@input)默认忽略 IME 中间态,只在compositionend或直接输入完成时触发——这反而比裸写oninput更安全。
但如果你手动绑定oninput并直接调用setState或v-model,就会高频重渲染,浏览器判定 DOM 被篡改,强制终止 IME 会话:光标跳走、候选框消失、值清空。
- React 函数组件中,用
useRef缓存isComposing状态,在compositionstart设为true,compositionend设为false - 所有清洗逻辑(截断、格式化、正则替换)都加守卫:
if (!isComposing.current) { /* 执行 */ } - 提交按钮点击时,别直接读
input.value,改用new FormData(form).get('field'),它内部等待 composition 结束
Firefox 和 Safari 对 input 事件的触发不一致
Firefox 在type="number"中对负号(-)、小数点(.)输入不触发input,只等失焦走change;Safari 在 date 或 contenteditable 区域中常漏首次输入或上屏事件。Chrome/Edge 则相对激进,每次按键都触发。
这意味着:仅靠input无法做到跨浏览器一致响应,尤其涉及数字、日期、富文本编辑时。
- 数字输入场景,必须监听
input+change+blur三者,任一触发都做校验 - date 类型不能只信
input,Safari 下需用change兜底,且注意 iOS 软键盘弹出时value可能滞后一帧 - contenteditable 完全不可靠,不同引擎(WebKit/Blink/Gecko)对光标、换行、候选框锚点处理差异极大,应避免用于表单主输入
实际中最容易被忽略的,是compositionend和blur的组合兜底——既不能只信input,也不能只靠change,更不能在中间态清洗 value。



















