阅读 143

input焦点跳动问题探索

前言

本来应该周末写完的组件调研input篇,不出意外的鸽了。在和室友相约卸载炉石拒绝浪费人生后,不想又投入到了金铲铲的怀抱,玩了一个周末的约德尔人,破口大骂sb才会再玩这个羁绊...

这篇,就算作Input组件调研的番外篇,就input在focus时,焦点的位置在前后跳动的问题进行一个整理。

start

focus到底是谁的小孩

之前,一直认为inputfocus是由click事件触发的,点一点,焦点就过去了。

直到接触input组件之后,才发现事情并不简单,菜鸡程序员好像又发现了新大陆,先写个htmlinput上绑定需要监听的事件,附上打印结果。

<body> <div>     <input type="text" value="11" id="ipt"> </div> <script>     ipt.onmouseup = function (e) {         console.log('up');     }     ipt.onmousedown = function (e) {         console.log('down');     }     ipt.onfocus = function () {         console.log('focus');     }     ipt.onclick = function () {         console.log('click');     } </script> </body> 复制代码

image.png

console中可以发现,事件触发的顺序mousedown - focus - mouseup - click

focus完了,click才姗姗来迟,足以证明孩子不是它的,是我让他喜当爹了。从结果中来看,focus事件只能是由mousedown触发的。

再做个亲子鉴定,给mousedown加上一个阻止默认事件,再点击看看结果,发现确实focus不触发了,证明之前的推论是正确的。

ipt.onmousedown = function (e) {     e.preventDefault()     console.log('down'); } 复制代码

image.png

input焦点位置异常。

这个其实很煎熬,因为我查了很多资料,也没有明白它的具体机制是怎么样的,只能通过举例子来说明一下。

1.有默认值的input初次调用focus

<body> <div>     <input type="text" value="11111" id="ipt"> </div> <div>     <button id="btn">test</button> </div> <script>     btn.onclick = function() {         ipt.focus();     } </script> </body> 复制代码

image.png

这个时候点击test按钮,光标位置会出现在首格。

解决方法也很简单,先把value置为空,focus之后,再把value放回去就可以了(setAttribute不行)

btn.onclick = function() {     ipt.value = '';     ipt.focus();     ipt.value = '11'; } 复制代码

如果用的是autoFocus属性,延迟赋值就可以解决了。

更改type后,手动focus输入框

p.onclick = function (e) {     const t = ipt.getAttribute('type');     ipt.type = t === 'password' ? 'text' : 'password';     ipt.focus();     ipt.setAttribute('type', t === 'password' ? 'text' : 'password') } 复制代码

这种情况在原生中,其实只要吧focus()setAttribute调换下位置,光标就会正常显示在最后了。

但是在react中,state都是延缓更新的,focus一般都会运行在前面,所以一种办法就是放到setState的回调函数中去调用focus

另一种就是阻止pmouseup的默认事件。

p.onmouseup = function (e) {     console.log('up');     e.preventDefault(); } 复制代码

inputfocus的状态下时,通过点击事件触发type的修改,或者触发setAttribute('value')的修改时(不包含ipt.value = ***')input光标就会前移到首位,解决方案就是阻止mouseup的默认事件。原理是啥,我也不知道= =,希望懂的大哥们可以告诉我一下。

在react中解决焦点问题

遇到的情况就是在input组件中新加password组件,通过点击小眼睛,来控制type的变更,达到显示和隐藏密码的效果。由于icon不属于input,所以正常点击的话会引起失焦。一般有2种方法来解决这个问题。

1.重新手动聚焦 -- 使用setState的回调函数,或者useEffect

changeType(e) {     this.setState({         type: (this.state.type === 'text' ? 'password' : 'text')     }, () => {         // focus光标在最后         this.inputRef.current.focus();     });     // focus光标在最前     // this.inputRef.current.focus(); } 复制代码

这里就举一个class写法的例子。如果使用hook写法useEffect的话,需要加个标记位判断更新时候才运行,不然挂载时候就会自动focus,官网上的hook教程中有写怎么操作。

但是手动focus会一个问题,因为组件中是可以传递自定义的onBluronFocus的,这种情况下,就会重新运行这2个函数,需要根据具体使用情况来判断是否合理。

使用e.preventDefault()阻止默认事件

这也是各个组件库都使用的方法。 通过在icon上绑定mouseupmousedown事件,通过e.preventDefault()阻止失焦和焦点跳动的问题。使焦点始终保持在input当前的位置。

<Icon   className="zent-input-icon"   type={icon}   onMouseUp={preventDefault}   onMouseDown={preventDefault}   onClick={onIconClick} /> 复制代码

end

起因是在新增password组件时候,发现了焦点前移的问题。然后在使用useEffect后,又看了各个组件库大佬们写的代码,发现了通过mouseupmousedown解决问题的办法,就来小小研究了一下,补一补基础。

input组件的调研篇也会尽量在这周写完。依旧是靠阅读大佬们的代码,寻求进步的一天~


作者:懒狗小前端
链接:https://juejin.cn/post/7030996134575226894

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐