最近做了一个移动端的搜索功能,带有suggest。实现上并没有什么可说的,但是在后续优化上,特别是在中文输入法的情况下的优化使我学到一些新东西,所以决定写一篇文章。

下面是我简化后的基本功能实现,监听输入框的input事件,当搜索框有输入时,根据输入内容和后端进行交互提供suggest,再监听keyup的事件,当用户敲击回车的时候,就进行一次搜索。注意其中suggest和search是两个自定义事件,并非原生事件。我们在实际生产环境里应该给自定义事件加上特殊前缀。

('#searchInput')
.on('input', function() {
    $(this).trigger('suggest');
})
.on('keyup', function(e) {
    var isEnterKey = e.keyCode === 13;
    if(isEnterKey) {
        $(this).trigger('search');
    }
})
.on('suggest', function() {
    ...
})
.on('search', function() {
    ...
})


做到这一步,基本功能就可用了。然后我们可以考虑做一些优化,优化点就是减少和后端非必要的的交互,我们一般有如下措施:

1.ajax缓存
2.trim操作防止空格产生的input事件
3.用time delay来优化用户输入过快频繁和后端发生的suggest询问
4.当用户当前输入法状态是中文时,在未选择词组到输入框之前不和后端进行任何交互
5.中文输入法状态下回车是将输入的字母填入输入框中,这时的回车不进行搜索

接下来我会就说说我对第4、5条的优化的实现。当我们把输入法切换为中文,然后进行输入,这种情况下还是会触发input事件,即便我们还没有选择词组。我们想要的结果是只有词组进入了输入框才向后端发起suggest询问。我们可以使用两个较新的事件来达到预期的效果:compositionstart和compositionend。

compositionstart
当浏览器有非直接的文字输入时, compositionstart事件会以同步模式触发.

compositionend
当浏览器是直接的文字输入时, compositionend会以同步模式触发.

上面是MDN上的解释,我也是第一次接触到上述事件。


('#searchInput')
.on('compositionstart', function() {
    $(this).data('notEnglishInputMethod', true);
})
.on('compositionend', function() {
    $(this).data('notEnglishInputMethod', false);
})


然后我们可以通过$(‘#searchInput’).data(‘notEnglishInputMethod’)来判断是否触发suggest。在input事件里加上这个条件。


('#searchInput').on('input', function() {
    if(!$(this).data('notEnglishInputMethod')) {
        $(this).trigger('suggest', value);
    }
})


这样我们的第4个问题总算解决了,现在中文输入法下敲击键盘不会进行suggest,直到选择了词组。还剩下第5个问题,在中文键入拼音展现可选词组的状态下回车不进行默认的搜索功能。

即便当前是中文输入法,我们的keyup事件同样会被触发。我试了半天都没找到很好的解决办法,后来我发现中文输入法事件下keydown事件里面所有按键的keyCode都等于229,于是我们可以通过这个差异来解决这个问题。我们给输入框再绑定一个keydown事件,并把当前的keyCode保存起来,然后在keyup事件里面来作比较,如果两者相等,基本可以确实是在直接输入的状态下,不相等则表示是在非直接输入的情况下,也就是中文输入法情况下。Show you the code!



('#searchInput')
.on('keydown', function(e) {
    $(this).data('lastKeydownCode', e.keyCode);
})
.on('keyup', function(e) {
    var isEnterKey = e.keyCode === 13;
    if(isEnterKey && e.keyCode === $(this).data('lastKeydownCode')) {
        $(this).trigger('search');
    }
})



通过上述的方法,我们基本上解决了中文输入法搜索带来的问题。希望能对你有小小的帮助。