JavaScript 输入中文时,拼音阶段会触发 input 事件

lonhon · 2018年03月05日 · 最后由 stick-yi 回复于 2018年04月09日 · 844 次阅读
本帖已被设为精华帖!

问题:

监听文本输入框的input事件,在拼写汉字(输入法)但汉字并未实际填充到文本框中(选词)时会触发input事件

** 需求:选词完成后触发input事件,只触发一次。 **

思路:

通过查阅资料得知在输入中文(包括语音识别时)会先后触发compositionstart、compositionend事件,类似于keydown和keyup的组合。

触发compositionstart时,文本框会填入 “虚拟文本”(待确认文本),同时触发input事件;在触发compositionend时,就是填入实际内容后(已确认文本)。

先看看 compositionstart 的描述 和 compositionend 的 描述

compositionstart 事件触发于一段文字的输入之前(类似于 keydown 事件,但是该事件仅在若干可见字符的输入之前,而这些可见字符的输入可能需要一连串的键盘操作、语音识别或者点击输入法的备选词)。

compositionend 当文本段落的组织已经完成或取消时,会触发该事件。

理解:

  compositionstart 在输入一段需要确认的文本如拼音to汉字、语音时会触发

  compositionend 在拼音选词完成、语音输入完毕时会触发

问题解决

至此,思路get: 声明一个标记flag,在compositionstart、compositionend两个事件过程之间的时候flag值为false,在input事件中通过flag的值来判断当前输入的状态。

OK,接下来贴出示例代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <script src="http://libs.baidu.com/jquery/1.8.3/jquery.min.js"></script>
        <title>lonhon</title>
    </head>
    <body>
    <input id="txt" type="text">
    <script>
        var flag = true;
        $('#txt').on('compositionstart',function(){
            flag = false;
        })
        $('#txt').on('compositionend',function(){
            flag = true;
        })
        $('#txt').on('input',function(){
            var _this = this;
            setTimeout(function(){
                if(flag){
                    console.log($(_this).val());
                }
            },0)
        })
    </script>
    </body>
</html>

上面代码经 @koushui 指出在FF下存在问题,个人认为应该是浏览器原因导致的差异造成,已修改input内部为

$('#txt').on('input',function(){
    var _this = this;
    setTimeout(function(){
        if(flag){
            flag = false;
            console.log($(_this).val());
        }
    },0)
})

效果图:

tips:

  为什么使用延时器?

  因为选词结束的时候input会比compositionend先一步触发,此时flag还未调整为true,所以不能触发到console,故用setTimeout将其优先级滞后。

有更好的意见or方法欢迎讨论。

共收到 6 条回复

可以,正缺少这样的实干家,赞一个

es6china 将本帖设为了精华贴 03月05日 11:40

学习了!😀

<html>
    <head>
        <meta charset="UTF-8">
        <script src="http://libs.baidu.com/jquery/1.8.3/jquery.min.js"></script>
        <title>lonhon</title>
    </head>
    <body>
    <input id="txt" type="text">
    <script>
        var flag = true;
        $('#txt').on('compositionstart',function(){
            flag = false;
        })
        $('#txt').on('compositionend',function(){
            flag = true;
        })
        $('#txt').on('input',function(){
            var _this = this;
            setTimeout(function(){
                if(flag){
                    console.log($(_this).val());
                    flag = false;
                }
            },0)
        })
    </script>
    </body>
</html>

火狐用楼主的代码会重复输入框内容 重复次数为字母数量 比如shu 他会在控制台输出3次 或 输入完美 重复了2次
所以我改了一下

koushui 回复

感谢指出,已修改,当时没考虑兼容 嘿嘿。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册