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


    本文转自:http://www.cnblogs.com/chyingp/p/3599641.html

    遇到这么个需求,允许用户修改自己的名片,名片最大长度支持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));
        }
    });

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

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>demo</title>
    
    </head>
    <body>
        <input id="text" placeHolder="最大支持24个字节" />
        <script type="text/javascript" src="jquery.js"></script>
        <script type="text/javascript">
         var Str = {
             byteLen : function (str, len){
                //正则取到中文的个数,然后len*count+原来的长度。不用replace
                var factor = len || 2;
                str += '';
                var tmp = str.match(/[^x00-xff]/g) || [];
    
                var count = tmp.length;
                return str.length + (factor-1)*count;
            },
            getMaxlen : function(str,maxlen){
                var sResult = '', L=0, i=0, stop = false, sChar;
                if(str.replace(/[^x00-xff]/g,'xxx').length <= maxlen){
                    return str;
                }
                while(!stop){
                    sChar = str.charAt(i);
                    //sResult+=sChar;
                    L+= sChar.match(/[^x00-xff]/) !== null ? 3 : 1;
    
                    if(L > maxlen){
                        stop = true;
                    }else{
                        sResult+=sChar;
                        i++;
                    }
                }
                return sResult;
            }
        };
        $('#text').on('input', function() {
            var value = $(this).val();
            if(Str.byteLen(value, 3)>24){
                $(this).val(Str.getMaxlen(value, 24));
            }
        });
        </script>
    </body>
    </html>
    View Code

     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”事件都是内部做了一堆兼容性处理的。假如这个需求是要兼容所有主流浏览器的话就真跪了,虽然这个迟早有一天会变成残酷的现实。

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

  • 相关阅读:
    如何在Oracle官网下载java的JDK最新版本和历史版本
    屏幕录制专家【Bandicam】
    Bandicam下载 + 破解
    华为荣耀7i手动更改DNS,提高网页加载速度
    SQL中使用GROUP BY注意事项
    JavaScript数据类型判断
    React.lazy和Suspense组合实现组件懒加载
    使用React+TypeScript构建自己的组件库
    leetcode-0101 对称二叉树
    leetcode-0543 二叉树的直径
  • 原文地址:https://www.cnblogs.com/zaofan/p/5201615.html
Copyright © 2020-2023  润新知