当前位置: 首页 > Web前端 > HTML

手写一个数字输入框3:痛点——输入法是魔鬼

时间:2023-04-02 12:58:55 HTML

前言最近用Polymer封装了纯数字输入框。在开发过程中,发现不是坑,还有很多值得研究的地方。本系列将分为4篇来讲述这段史诗般的踩坑经历:[《动手写个数字输入框1:input[type=number]的遗憾》](http://www.cnblogs.com/fsjohn...《动手写个数字输入框2:起手式——拦截非法字符》《动手写个数字输入框3:痛点——输入法是个魔鬼》《动手写个数字输入框4:魔鬼在细节——打磨光标位置》IE的进阶性hardwork最后控制只能输入数字,但是只要用户启用了输入法,他就可以轻松突破我们的包围圈:-<心碎满地都是,这就是为什么我们会想有没有API可以禁用输入法?答案是肯定的,但奇怪的是,只有IE支持。value*normal:normalIMEstatus*active:激活本地语言输入法*inactive:激活非母语输入法*disabled:禁用IME*/ime-mode:disabled;}其他浏览器都是呵呵...没办法,只好补救~因为chrome、firefox等无法通过styleime-mode进行处理,所以想着照葫芦画瓢,同样在keydown事件中对具体的keyCode进行拦截过滤。谁知道在输入法中按下字符键时会发生keydown事件的keyCode始终为229,规则是:当按下字符键时,keydown中的keyCode始终为229,key为Undefined;并且在keyup中得到了正确的keyCode,key就是正确的字符。当按下enter和shift时只触发keydown不会触发keyup,keyCode为229。因此,我们能做的就是将keyup事件作为事后补救措施;在keydown中拦截输入法中输入的enter和shift键事件,然后触发keyup事件进行补救。废话少说,上代码!constkeyCode=anyPass(prop('keyCode'),prop('which'))constisBackspace=eq(8),isDelete=eq(46),isArrowLeft=eq(37),isArrowRight=eq(38)isArrowUp=eq(39)isArrowDown=eq(40)isTab=eq(9)isHome=eq(36)isEnd=eq(35)constisValidStr=precision=>a=>RegExp("^[+-]?[0-9]*"+(精度?"(\\.[0-9]{0,"+精度+"})?":"")+"$")。test(a)//获取min,max,precision值constlensTarget=lens(a=>a.target||a.srcElement),lensMin=lens(a=>Number(a.min)||Number(attr(a,'min'))||Number.MIN_SAFE_INTEGER),lensMax=lens(a=>Number(a.max)||Number(attr(a,'max'))||Number.MAX_SAFE_INTEGER),lensPrecision=lens(a=>Number(a.precision)||Number(attr(a,'precision'))||0),lensValue=lens(a=>a.value,(o,v)=>o.value=v),lensDataValue=镜头(a=>a&&a.getAttribute('数据值'),(a,v)=>a&&a.setAttribute('数据值',v))constlensTargetMin=lcomp(lensTarget,lensMin),lensTargetMax=lcomp(lensTarget,lensMax),lensTargetPrecision=lcomp(lensTarget,lensPrecision),lensTargetValue=lcomp(lensTarget,lensValue)constisIME=eq(229)constisValidChar=c=>/[-+0-9.]/.test(c)constinvalid2Empty=c=>isValidChar(c)?c:''constrecoverValue=v=>flatMap(CharSequence(v),invalid2Empty)//是否激活IMEconstisInIME=comp(isIME,keyCode)//是否为功能键,isFnKey=comp(anyPass(isArrowLeft),isArrowRight,isArrowUp,isArrowDown,isBackspace,isDelete,isHome,isEnd),keyCode)$('input[type=text]').addEventListener('keydown',e=>{varel=视图(lensTarget)(e),val=view(lensTargetValue)(e)//暂存value值,如果keyup有问题,可以恢复出厂设置set(lensDataValue)(el)(val)if(isInIME(e)){fireKeyup(el)}})$('输入[类型=文本]').addEventListener('keyup',e=>{if(isFnKey(e))returnvarel=view(lensTarget)(e),v=view(lensValue)(el),p=view(lensTargetPrecision)(e),isValid=isValidStr(p),max=view(lensMax)(el),min=view(lensMin)(el)varval=recoverValue(v)varsetVal=set(lensValue)(el)if(isValid(val)){if(val!==v){setVal(val)}else{varn=Number(v)if(!gte(max)(n)){setVal(max)}if(!lte(min)(n)){setVal(min)}}}else{setVal(attr(el,'data-value'))}})附录:工具函数//工具函数,请忽略我:Dconstcomp=(...fns)=>(...args)=>{让len=fns.长度while(len--){args=[fns[len].应用(null,args)]}返回参数。长度>1?参数:参数[0]}constisSome=x=>'undefined'!==typeofx&&x!==nullconstinvokerImpl=n=>o=>m=>(...args)=>{让args4m=args.splice(0,n),次=Number(args[0])||1、ret=[]while(times--){vartmpRettry{tmpRet=o[m].apply(o,args4m)}catch(e){tmpRet=void0}ret.push(tmpRet)}returnret.length>1?ret:ret[0]}constcurry2Partial=fn=>(...args)=>{让c=true,i=0,l=args.length,f=fn对于(;c&&iargs.reduce((accu,x)=>accu&&x,true)const或=(...args)=>args.reduce((accu,x)=>accu||x,false)constallPass=(...fns)=>v=>fns.reduce((accu,x)=>accu&&x(v),true)constanyPass=(...fns)=>v=>fns.reduce((accu,x)=>accu||x(v),false)consteq=a=>b=>a===bconstgt=a=>b=>a>bconstgte=a=>anyPass(eq(a),gt(a))constlt=a=>b=>aanyPass(eq(a),lt(a))constprop=k=>o=>o[k]constlens=(g,s)=>({getter:g,setter:s})constlensPath=(...args)=>({getter:a=>args.减少((accu,x)=>accu&&accu[x],a)})constlcomp=(...lenses)=>lensconstview=lenses=>a=>{if(!~Object.prototype.toString.call(lenses).indexOf('数组')){lenses=[lenses]}returnlenses.reduce((accu,lens)=>accu&&lens.getter(accu),a)}constset=lens=>a=>v=>{如果(!~Object.prototype.toString.call(lenses).indexOf('Array')){lenses=[lenses]}varsetLens=lens.pop()varo=view(lenses)(a)if(o){setLens.setter(o,v)}}const$=invoker(1,document,"querySelector")constattr=(o,a)=>invoker(1,o,'getAttribute')(a)constflatMap=(functor,f)=>{returnfunctor.flatMap(f)}functionCharSequence(v){if(thisinstanceofCharSequence);elsereturnnewCharSequence(v)this.v=v}CharSequence.prototype.flatMap=function(f){returnthis.v.split('').map(f).join('')}constfireKeyup=(el)=>{if(KeyboardEvent){//DOM3vare=newKeyboardEvent('keyup')el.dispatchEvent(e)}else{//DOM2vare=document.createEvent('KeyboardEvent')e.initEvent('keyup',true,true)el.dispatchEvent(e)}}待续?这里我们已经成功控制了IME下的输入,虽然事后修复导致用户输入闪烁:D结束了吗?当然不是。用户输入时,光标位置是随机的,所以还存在以下问题:在预判断keydow中的值的合法性时,假设光标位置在行尾,会导致报错预言;当在keyup中重新赋值时,会导致光标移动到行尾,严重打断用户的输入过程;type=text会导致数字键盘在移动端不自动显示。总结以上问题我们稍后会继续讨论,敬请期待!尊重原创,转载请注明出处:http://www.cnblogs.com/fsjohn...^_^FatBoyJohn