input事件中文触发多次难题钻探,谈什么界定输入框输入类型

By admin in 4858美高梅 on 2019年4月13日

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

相遇这样个须求,允许用户修改自身的片子,名片最大尺寸协理柒个汉字(贰多少个字节),当用户输入超过八个字节,则不允许用户继续输入。

  大家在网页中日常会遇见实时搜索的情况,或许其余类似需求input实时响应的难题,一般景色下,大家是应用input和propertychange事件来监听input内容的转移来响应,不过有二个题目正是当输入汉字的时候,大概大家要输入
‘实时’ 的时候,大家的input框中会出现 ‘shishi’直到大家的空格才会变成
‘实时’,那也就意味着大家各个响应了
‘s’,’sh’,’shi’,’shis’,’shish’,’shishi’,’实时’,前面包车型地铁结果肯定不是大家要求的
,造成了我们很频繁不算的付出,倘若是接口请求,那更可怜,多发了好多次请求。

input事件中文触发多次难题钻探,谈什么界定输入框输入类型。bug的发生和修改

  上周周围周末休养的时候,二个同事跑过来了,对自身说:“Allen啊,有四个页面出难点了,火狐浏览器全部的input都没办法输入了。”我一听,是还是不是您给加了什么性质,让input输入框只读了呀。看了须臾间代码,很寻常的三个输入框,并且CSS写的也很健康。

<input id="ipt-message" type="text" placeholder="请输入身高" />

  不过运营之后发现不可能输入任何事物,包罗字母、符号、数字(后来实验发现,输入了汉字之后方可输入符号和数字,那几个临时未察觉原因)。那么难题就来了,肯定是js部分的题材了。当时自个儿就猜大致是做了限制,然而及时小编要么相比相信同事写的代码的。作者就面对着多少个js文件3个二个的看,3个几千行行代码,知道笔者见到了上边这段代码:

$("input[type='text']").keypress(function (e) {
    if (!String.fromCharCode(e.keyCode).match(/[0-9\.]/)) {
        return false;
    }
})    

  尽管当时没表达那段代码的景况,可是直觉告诉自个儿找到原因了。小编把那段代码复制出来还原了须臾间,大致意思正是具有的公文输入框在keypress事件触发这一个函数,使用正则验证输入的状态,只好输入小鼠和小数点。不过当运营的时候难点应运而生了,bug出现了,那么难题找到了,正是那四行代码导致的,在那堆js代码中去掉那4行之后就未有了难题。

  之后作者切磋出错的原因时意识,e.keyCode在谷歌(Google)时经常突显,可是在火狐浏览器下就会冒出难题了:

 

谷歌浏览器

火狐浏览器

IE11浏览器

按键“a”

keydown:keyCode为65,charCode为0

keypress:keyCode为97,charCode为97

keyup:keyCode为65,charCode为0

 keydown:keyCode为65,charCode为0

keypress:keyCode为0,charCode为97

keyup:keyCode为65,charCode为0

 keydown:keyCode为65,charCode为0

keypress:keyCode为97,charCode为97

keyup:keyCode为65,charCode为0

 按键“1”  

keydown:keyCode为49,charCode为0

keypress:keyCode为49,charCode为49

keyup:keyCode为49,charCode为0

 

keydown:keyCode为49,charCode为0

keypress:keyCode为0,charCode为49

keyup:keyCode为49,charCode为0

 

keydown:keyCode为49,charCode为0

keypress:keyCode为49,charCode为49

keyup:keyCode为49,charCode为0

 按键“Backspace”  

keydown:keyCode为8,charCode为0

keypress未触发

keyup:keyCode为8,charCode为0

 

keydown:keyCode为8,charCode为0

keypress:keyCode为8,charCode为0

keyup:keyCode为8,charCode为0

 

keydown:keyCode为8,charCode为0

keypress为触发

keyup:keyCode为8,charCode为0

  那么难点就找到原因了,通过String.fromCharCode(e.keyCode)是心有余而力不足形成包容火狐浏览器再次回到按键值,因为当输入数字和字母时,其keyCode都为0。

  因而,作者修改了一下以此代码:

$("input[type='text']").keypress(function (e) {
    var code = e.charCode || e.originalEvent.charCode;
    if (code != 0) {
        if (!String.fromCharCode(code).match(/[0-9\.]/)) {
            return false;
        }
    }
}) 

  original伊芙nt是jquery对原生event属性的包裹。“code !=
0”这几个论断是在火狐浏览器下对是还是不是按键为“Backspace”的判定,借使未有那么些论断,会造成Backspace键不能够采用,不可能删除那一个情况的产生。

4858美高梅 1

早期的思路:oninput你好

很普遍的急需,觉得相当熟谙,监听input事件,当输入内容产生变化的时候,得到用户输入内容,并开始展览截断操作(如果超越的话)。首要代码如下。壹切体现那么美好,直到汉语输入法出现。

ps:本文用例均在
chrome 版本 3三.0.1750.14陆下测试

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

全体代码如下,有趣味可以看下:

4858美高梅 24858美高梅 3

<!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>

壹体化代码

  最早在此之前有一个稍微能立异的化解方案正是相当1个定时器延时执行,那样能减小请求次数,然而这一个收缩是不分情况的减少,如故治标不治本。

谈限制输入框输入类型

  其实不管使用哪类办法来界定输入框的输入的项目,都离不开keyup、keypress、keyup和相比较少见的textInput三个事件来触发。在那之中,前多个为顺序浏览器联合帮助的,而textInput仅有IE玖+,Safari和Chrome,那也规范比较普遍的浏览器(或其基础)。前多个事件为键盘事件,最终1个为文本事件。其触发的逐一为keydown(按键按下)——>keypress(按键值插入文本)——>textInput(按键值插入文本)——>keyup(按键弹起)。textInput和keypress的发出很1般,但两者照旧有分别:任何能够取得主题的因素都得以触发keypress事件,但只有可编写制定区域才能触发textInput事件。textInput事件只会在用户按下能够输入实际字符的键时才会触发,而keypress事件则在按下那多少个能够影响文本展现的键时也会接触(比如退格键)。

  在其实的操作中,大家会发将来输入汉语的时候,只用按键事件对其开始展览接触限制输入框的操作经验10分倒霉。比如上边的代码,只在keypress事件触发限制,当大家输入法切换在汉语时,按下字母之后按空格键恐怕“shift”键,会意识大家的限定失效了。

4858美高梅 4

唯独在许多情形下,只供给输入到输入框的国语字符。

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));
        }
    });

 

  后天有时看到多少个事件,发现能够周密解决那种题材。大家来看一下那多少个事件

原生js

  由此为了更加好的经验,大家须求更加多的轩然大波触发限制,达到大家的指标。因而,大家应在触发keypress后在对将要插入文本框的值进行1边过滤。就拿上文的原则只可以输入数字和小数点来说,大家需求在textIput事件发生时判断一下文本框的value值,使用正则举行一下过滤。代码如下:

    var EventUtil = {
        addHandler: function (element, type, handler) {
            if (element.addEventListener) { //DOM2级
                element.addEventListener(type, handler, false);
            } else if (element.attachEvent) { //DOM1级
                element.attachEvent("on" + type, handler);
            } else {
                element["on" + type] = handler; //DOM0级
            }
        },
        removeHandler: function (element, type, handler) { //类似addHandler
            if (element.removeEventListener) {
                element.removeEventListener(type, handler, false);
            } else if (element.detachEvent) {
                element.detachEvent("on" + type, handler);
            } else {
                element["on" + type] = null;
            }
        }
    }
    var textbox = document.getElementById('input');
    EventUtil.addHandler(textbox, 'textInput', function (e) {
        e.target.value = e.target.value.replace(/[^0-9\.]/g, '')
    })

  利用事件监听把绑定textIput事件,当触发时再对其value过滤一下。结果恐怕不错的:

4858美高梅 5

  不过在上文提到过,textInput属性对火狐浏览器无包容,由此,大家就要求采纳keyup对其展开代替(但意义倒霉):

textbox.onkeyup=function (e) {
    e.target.value = e.target.value.replace(/[^0-9\.]/g, '')
}

  附完整代码,原生js完结:代码地址。

化解办法:

下边是输入进程中的截图。能够看出,用户使用中文输入法输入的经过中,“input”事件被不断地接触着,那会推动怎样难题呢?相信您曾经想到了——会促成程序对当前用户输入字符实际尺寸的误判。比如用户输入“程序猿”七个男子汉,实际占有捌个字节,但对上面的主次来说,取到的字节数为”chengxuyuan”.length

1一。在用户输入达到边界值时,就会莫明其妙地将用户的输入截断,导致汉语输入不大概继续(感兴趣的校友能够友善试下)

4858美高梅 6

 

  compositionstart , compositionupdate ,compositionend    

Vue的自定义指令

  不难少量的input大家能够动用双向绑定后,watch到变化实行限定,如下:

<input id="ipt" type="text" v-model="iptVal"/>
<script>
    var qwe=new Vue({
        el:'#ipt',
        data(){
            return{
                iptVal:''
            }
        },
        watch:{
            iptVal(val){
                this.iptVal=val.replace(/[^0-9\.]/g, '')
            }
        }
    })
</script>

  然而,当面对大气的input输入框,大家更向往用简短的方法去化解,甚至简单到只写二个限令(比如v-limit)就能够。那样,大家就需求用到自定义指令的知识(可参照小编的博客《Vue的土著人指令和自定义指令》)。

  这一个value是随着输入不断更新的,由此,我们需求选拔update那个钩子函数:

    Vue.directive('limit', {
        update: function (el) {
            el.onkeypress = function (e) {
                var code = e.charCode;
                if (code != 0) {
                    if (!String.fromCharCode(code).match(/[0-9\.]/)) {
                        return false;
                    }
                }
            }
            el.addEventListener('textInput', function (e) {
                e.target.value = e.target.value.replace(/[^0-9\.]/g, '')
            })
            el.onkeyup = function (e) {
                e.target.value = e.target.value.replace(/[^0-9\.]/g, '')
            }
        }
    })

  此时,调用的法子尤其不难,只供给追加“v-limit”这么些命令即可。

<input id="ipt" type="text" v-model="iptVal" v-limit />

  附完整代码,基于Vue的自定义指令的贯彻:代码地址。

透过查看资料获悉在输入普通话(包蕴语音识别时)会先后触发compositionstart、compositionend事件,类似于keydown和keyup的组成。

化解思路1: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事件触发,就停下对输入字符的截断操作,而是耐心等待用户输入的收尾

4858美高梅 7

按下空格键,中文输入完结,此时再去开始展览字符长度的判读和截断

4858美高梅 8

 

   compositionstart 官方表明 : 触发于壹段文字的输入在此以前(类似于 keydown 事件,可是该事件仅在若干可知字符的输入从前,而这么些可知字符的输入也许要求一种类的键盘操作、语音识别可能点击输入法的备选词),通俗点,假诺大家要输入一段普通话,当我们按下率先个字母的时候触发

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

未完的探赜索隐

正如本文最前边强调的,本文的用例都是在chrome特定版本下进展测试,鲜明compositionstart、compositionend并不是2个很是全数浏览器的方案。包括jQuery的“input”事件都以内部做了一群包容性处理的。要是这么些必要是要协作全体主流浏览器的话就真跪了,就算这一个迟早有1天会变成狂暴的求实。

故而呢,探索还将持续:是还是不是有很是全数主流浏览器的方案,求路过的弟兄们支招。

 

本文代码示例参见附属类小部件

  相应的compositionupdate在大家中文开头输入到截至完结的每3遍keyup触发。

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

  而compositionend则在我们实现方今中文的输入触发

compositionstart 事件触发于1段文字的输入此前(类似于 keydown 事件,但是该事件仅在多少凸现字符的输入以前,而这个可见字符的输入或者须要层层的键盘操作、语音识别可能点击输入法的备选词)。

  正题来了,通过地点的轩然大波大家就足以全面包车型客车消除普通话输入的响应难题了,从compositionstart触发起来,意味着汉语输入的起先且还没到位,所以此时大家不须求做出响应,在compositionend触发时,表示中文输入实现,那时我们能够做相应事件的处理。

compositionend 
当文本段落的团组织曾经到位或收回时,会触发该事件。

  所以大家得以设置一个变量,或许给input定义三个属性,在compositionstart到compositionend之间对input事件不做出响应。看之下代码

接触如下:

 

4858美高梅 9

$('input').on({
    input : function(e){        
        var flag = e.target.isNeedPrevent;
        if(flag)  return;     
        response() 
    },
    compositionstart : function(e){
        e.target.isNeedPrevent = true ;
    },
    compositionend : function(e){
        e.target.isNeedPrevent = false;        
    }
})
function response(){
    $('div').append('<p>事 件触发</p>')
}

即每按下2个拼音字符,都会触发input事件,选择普通话也会触发input事件,不过在剔除输入框内中文的时候不会接触compositionend 事件,所以取得输入框内容如故要放到input事件里。

 

思路: 声可瑞康(Karicare)个标记flag,在compositionstart、compositionend多少个事件经过里面包车型客车时候flag值为false,在input事件中通过flag的值来判定当前输入的境况。

  大家经过compositionstart,compositionend事件来安装flag,判断是或不是正在拓展输入汉语以控制input事件的响应,看上去未有失常态,但其实执行时会发今后谷歌(谷歌)浏览器中input执行各种要先于compositionend,火狐执行顺序正常,但compositionend会响应四回。那就招致谷歌浏览器中输入汉字不会响应input事件。当然也足以在compositionend事件中再进行2次response事件,那样的题材是在火狐浏览器中会多执行3次response,显著不是最优方案。

4858美高梅, 

  经过试验,发现keyup和compositionend事件实施顺序在各大浏览器都保持1致,于是大家改成如下代码:

    var flag = true;
       $('#input').on({
            compositionstart:function(){flag = false;},
            compositionend:function(){flag = true;},
            input:function(){
                var _this = this;
                setTimeout(function(){
                    if(flag){
                        console.log($(_this).val());
                    }
                },0);
            }
        });
$('input').on({
    keyup : function(e){        
        var flag = e.target.isNeedPrevent;
        if(flag)  return;     
        response() 
    },
    compositionstart : function(e){
        e.target.isNeedPrevent = true ;
    },
    compositionend : function(e){
        e.target.isNeedPrevent = false;  

    }
})
function response(){
        $('div').append('<p>事 件触发</p>')
} 

 4858美高梅 10

  那样在各类浏览器基本保持一致了(包容compositionstart的浏览器)。但是keyup有1个难题,比如通过鼠标复制粘贴的时候并不对应keyup事件,所以地点的业务我们还索要再优化下,keyup相应按键事件,input响应除了keyup之外的转变事件。代码如下

 tips:
  为何使用延时器?
  因为选词甘休的时候input会比compositionend先一步触发,此时flag还未调整为true,所以不能够触发到console,故用setTimeout将其优先级滞后。

$('input').on({
    keyup : function(e){        
        var flag = e.target.isNeedPrevent;
        if(flag)  return;     
        response() ;
        e.target.keyEvent = false ;

    },
    keydown : function(e){
        e.target.keyEvent = true ; 
    },
    input : function(e){
        if(!e.target.keyEvent){
            response()
        }        
    },
    compositionstart : function(e){
        e.target.isNeedPrevent = true ;
    },
    compositionend : function(e){
        e.target.isNeedPrevent = false;

    }
})
function response(){
        $('div').append('<p>事 件触发</p>')
}

4858美高梅 11

  从日前必要能够完全实现了。

 

在线预览:

4858美高梅 12

 

 

参考:

参考小说:

 

  

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有