composition 与 input 时序
输入法组合期间,输入框里的文本可能只是候选内容。把每次 input 都当作最终值,会在中文、日文或韩文输入时提前提交搜索或校验。
最小实验:记录组合状态
保存为 composition.html 后用浏览器打开:
html
<label>关键词 <input id="keyword" /></label>
<pre id="log"></pre>
<script>
const input = document.querySelector('#keyword')
const log = document.querySelector('#log')
let composing = false
const write = (name, value) => {
log.textContent += `${name}: ${JSON.stringify(value)} composing=${composing}\n`
}
input.addEventListener('compositionstart', () => { composing = true; write('compositionstart', input.value) })
input.addEventListener('compositionupdate', () => write('compositionupdate', input.value))
input.addEventListener('input', () => write('input', input.value))
input.addEventListener('compositionend', () => { composing = false; write('compositionend', input.value) })
</script>使用中文输入法输入“北京”,观察 compositionupdate、input、compositionend 的顺序。应用搜索请求时,只在 !composing 时提交;不要依赖某一个浏览器的事件顺序作为唯一判断。
机制与边界
compositionstart 到 compositionend 是一次组合会话。input 反映编辑值变化,但不保证它就是用户最终确认的词。剪贴板、语音输入和移动端键盘可能没有完全相同的事件序列,因此最终策略应同时处理普通 input 和组合状态。
练习
- 给实验增加
commit(value),验证组合期间不触发提交,compositionend后只提交一次。 - 使用退格、粘贴和语音输入,记录与中文输入不同的事件序列。
- 设计一个超时取消,确保离开页面后不会提交过期搜索。