在做搜索等功能时,很多时候我们需要实时获取用户输入的值,而常常会得到类似 w'm
这样的拼音。为了解决这个问题,我在网上搜索了下相关问题,发现了两个陌生的事件:compositionstart
和 compositionend
。
compositionstart & compositionend
在 MDN
上找到了关于他们的描述,compositionstart 和 compositionend。简单点描述如下:
- compositionstart:在输入中文或者语音等需要等待一连串的输入的操作之前,
compositionstart
事件会触发。 - compositionend:在输入中文或者语音等完毕或取消时,
compositionend
事件会触发。
input 和 compositionend 的触发顺序导致的问题
注:以下为 chrome
浏览器下的测试结果,关于其他浏览器请看兼容说明!
和大多数人的想法一样,我考虑使用一个布尔值来判断是否在等待输入法的输入,然后在 input
事件中根据其布尔值决定是否获取输入的值,初始代码如下:
var isInputZh = false;
elem.addEventListener('compositionstart', function (e) {
isInputZh = true;
}, false);
elem.addEventListener('compositionend', function (e) {
isInputZh = false;
}, false);
elem.addEventListener('input', function (e) {
if (isInputZh) return;
var value = this.value;
console.log(value);
doSomething(value);
}, false);
嗯。。看起来好像没啥问题,运行后,却有些让人摸不着头脑。在一段中文输入完毕后却并没有在控制台输出任何数据。嗯。。测试后发现 compositionend
事件是在 input
事件之后触发的。
解决方法
最后只能用常规方法去解决:在 compositionend
和 input
事件中都得加入对输入值的处理。代码如下:
var isInputZh = false;
var search = document.querySelector('input');
search.addEventListener('compositionstart', function (e) {
isInputZh = true;
}, false);
search.addEventListener('compositionend', function (e) {
isInputZh = false;
doSomething(search.value);
}, false);
search.addEventListener('input', function (e) {
if (isInputZh) return;
var value = this.value;
doSomething(value);
}, false);
关于兼容说明
以上测试是在 chrome
浏览器下进行的,在 Firefox
和 Edge
浏览器下发现 input
事件在 compositionend
事件之后触发,且在输入数字时发现 Firefox
和 Edge
也会触发 compositionend
事件,以上内容仅在 chrome
浏览器中适用。
写在最后
原文发在 github。如果大家有什么好的解决方案欢迎在评论中提出。