正确做法是监听compositionstart、compositionupdate(可选)、compositionend三件套,用isComposing标志位忽略组合期间input事件,submit/blur时兜底检查,并优先使用FormData获取值。

compositionstart/compositionend 必须成对监听
中文输入法下,用户敲“shangh”,还没按空格,input 事件完全不触发,DOM value 也卡在旧值——这不是 bug,是浏览器对 Composition API 的标准行为。只监听 input,等于默认放弃拼音阶段的所有中间状态。
正确做法是三件套:监听 compositionstart 标记进入组合模式;可选监听 compositionupdate(用于获取当前拼音串);必须监听 compositionend,此时 event.target.value 才是最终上屏内容。
-
compositionstart触发时,缓存当前value,设isComposing = true - 期间所有
input事件都应忽略(或仅作轻量记录),避免把“nihao”当真实输入处理 -
compositionend触发后,立刻读取新value,并设isComposing = false - 别在
compositionstart里清掉防抖定时器——否则用户中途切走,拼音过程中的修改就丢了
submit 和 blur 事件必须兜底
用户打完“上海”,直接点提交按钮,form.submit() 可能抢在 compositionend 前执行,导致发出去的还是空值或上一个词。同理,失焦(blur)时若只等 input,也会漏掉最后一次上屏。
两个兜底动作缺一不可:
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 提交前检查:
if (input.isComposing || isComposing),是则e.preventDefault(),等compositionend后再手动form.submit() -
blur时对比当前value和上次缓存值,有变化就立即触发校验或保存逻辑 - 更稳妥的取值方式:
new FormData(form).get('field')—— 它内部会等待 composition 结束,比直接读input.value可靠
iOS Safari 和安卓 WebView 的 value 滞后问题
软键盘弹出瞬间,iOS Safari 和部分安卓 WebView 中 input.value 可能卡住一帧,尤其在快速切换输入法或连打时。在 focus 或 touchstart 回调里立刻读 value,大概率拿到过期内容。
微任务延迟是最低成本解法:
- 不用
setTimeout(fn, 0),改用Promise.resolve().then(() => console.log(input.value)) - 安卓端可监听
resize事件(软键盘弹出会改变 viewport 高度),作为 value 同步的辅助时机 - iOS 必须依赖
compositionend+input组合,不能只信后者
富文本 contenteditable 里的组合状态更难判断
在 contenteditable 区域,element.isComposing 在 Chrome/Firefox 里可用,但 Safari 不支持;且编辑器常自己劫持粘贴、回车等行为,进一步打乱事件流。
实操中建议:
- 自己维护
isComposing标志位,靠compositionstart/compositionend显式开关 - 不要在
compositionstart后立刻清空编辑器内容或重置光标——用户可能只是临时切出输入法 - 如果用 Quill / CKEditor5,优先调它们的 API 获取内容(如
quill.getText()或editor.getData()),这些方法内部已处理 composition 状态


















