经验总结:应对中文输入法的字符串截断方案(带代码示例)

遇到这么个需求,允许用户修改自己的名片,名片最大长度支持8个汉字(24个字节),当用户输入超过8个字节,则不允许用户继续输入

最初的思路:oninput你好

很常见的需求,觉得驾轻就熟,监听input事件,当输入内容发生变化的时候,获得用户输入内容,并进行截断操作(如果超出的话)。主要代码如下。一切显得那么美好,直到中文输入法出现。

ps:本文用例均在 chrome 版本 33.0.1750.146下测试

$('#text').on('input', function() {
    var value = $(this).val();
    if(Str.byteLen(value, 3)>24){
        $(this).val(Str.getMaxlen(value, 24));
    }
});

完整代码如下,有兴趣可以看下:

经验总结:应对中文输入法的字符串截断方案(带代码示例) 完整代码

oninput的局限:中文输入法带来的难题

上面的解决方案对于普通的文本输入,如英文字母、数字等的输入是ok的。但当用户通过中文输入法(比如QQ拼音)时,就会遇到一些问题,我们简单改下上面的代码,看看究竟会有什么问题。就加多了个log打印。

经验总结:应对中文输入法的字符串截断方案(带代码示例)
    $('#text').on('input', function() {
        var value = $(this).val();
        console.log('当前输入:'+value);  // 打印当前输入的值
        if(Str.byteLen(value, 3)>24){
            $(this).val(Str.getMaxlen(value, 24));
        }
    });
经验总结:应对中文输入法的字符串截断方案(带代码示例)

 

下面是输入过程中的截图。可以看到,用户使用中文输入法输入的过程中,“input”事件被不断地触发着,这会带来什么问题呢?相信你已经想到了——会导致程序对当前用户输入字符实际长度的误判。比如用户输入“程序猿”三个汉子,实际占用9个字节,但对上面的程序来说,取到的字节数为"chengxuyuan".length == 11。在用户输入达到边界值时,就会莫名其妙地将用户的输入截断,导致中文输入无法接续(感兴趣的同学可以自己试下)

经验总结:应对中文输入法的字符串截断方案(带代码示例)

 

解决思路一:compositionstart、compositionend

在万能的幼稚园群里抛出问题后,有个兄弟提出了个方案:可以采用compositionstart、compositionend来捕获IME(input method editor)的启动和关闭事件。说实话,这两事件听都没听过,但既然有这么个解决方案,暂且试一下,再次修改代码

经验总结:应对中文输入法的字符串截断方案(带代码示例)
$('#text').on('input', function() {
    if($(this).prop('comStart')) return;    // 中文输入过程中不截断

    var value = $(this).val();
    console.log('当前输入:'+value);
    if(Str.byteLen(value, 3)>24){
        $(this).val(Str.getMaxlen(value, 24));
    }
}).on('compositionstart', function(){
    $(this).prop('comStart', true);
    console.log('中文输入:开始');
}).on('compositionend', function(){
    $(this).prop('comStart', false);
    console.log('中文输入:结束');
});
经验总结:应对中文输入法的字符串截断方案(带代码示例)

 

输入过程截图如下,可以看到,当compositionstart事件触发,就停止对输入字符的截断操作,而是耐心等待用户输入的结束

经验总结:应对中文输入法的字符串截断方案(带代码示例)

按下空格键,中文输入结束,此时再去进行字符长度的判读和截断

经验总结:应对中文输入法的字符串截断方案(带代码示例)

 

未完的探索

正如正文最前面强调的,本文的用例都是在chrome特定版本下进行测试,显然compositionstart、compositionend并不是一个兼容所有浏览器的方案。包括jQuery的“input”事件都是内部做了一堆兼容性处理的。假如这个需求是要兼容所有主流浏览器的话就真跪了,虽然这个迟早有一天会变成残酷的现实。

所以呢,探索还将继续:是否有兼容所有主流浏览器的方案,求路过的兄弟们支招。

 

上一篇:PgSQL · 捉虫动态 · 执行大SQL语句提示无效的内存申请大小


下一篇:大数据创新衍生无限可能:第二届全球大数据峰会在成都隆重举行