1.问题描述展示

示例代码所做限制为不允许输入字母d,其他限制规则可以根据需求自己调整,使用React编写,其他框架或原生均可根据该代码理解原理进行转变,特意使用了中文键盘可以看到输入框下面白色框闪出,就是我按下了键盘d键

1) gif图示例

2)代码
import { useState } from "react"
export default function () {
const [value, setValue] = useState(1234)
const onChange = (e) => {
const inputValue = e.nativeEvent.target.value
const value = inputValue.replace('d', '')
setValue(value)
}
return <div style={{marginTop:200}}>
<h3>焦点修改实例:不允许输入字母 d 无处理情况</h3>
<input value={value} onChange={onChange}></input>
</div>
}
3)原因分析

假设目前输入值为1234,光标移动到2后面并输入字母d ,此时输入框得到的输入值为12d34,而我们通过代码将本来应该是12d34的值修改为了1234,也就导致了光标定位到了最后一位

之所以这样处理,猜想大概是因为通过代码进行值的修改的时候存在多种情况比如

a. 1234 => 12456 位数增多

b. 1234 => 12 位数变少

c. 1234 => 5678 值全变化

浏览器实现时为了统一这种情况 只要当浏览器输入框获取的输入值与设置的值不等的时候都重置光标位置

react使用value对输入框输入值做控制的流程为: (以输入框已经输入1234 光标移动到2后面输入d为例)

1.按下d键

2.输入框获得值12d34,但是此时输入框的值受value控制,onChange事件中如果不对value做修改则不会改变输入框实际展示值 (也就是说12d34浏览器输入框内部已经获取到的值为12d34,只是页面并未变化,页面变化由input上的value控制)

3.输入框onChang事件触发,此时代码处理,会将输入框获取值由本应该设置为12d34,修改为了1234,光标重置到最后面 (即输入框内部获取的值如果不等于value值就会光标重置到最后面)

2.解决方案

1)宏任务延时处理

原理为通过input.setSelectionRange改变光标位置,具体api细节自行百度参考文档

import { useState } from "react"
export default function () {
const [value1, setValue1] = useState(1234)
const onChange1 = (e) => {
const start = e.target.selectionStart
const inputValue = e.nativeEvent.target.value
const value = inputValue.replace('d', '')
const input = e.nativeEvent.target
setValue1(value)
setTimeout(() => {
inputValue.includes('d') && input.setSelectionRange(start - 1, start - 1)
}, 0)
}
return <div style={{marginTop:200}}>
<h3>焦点修改实例:不允许输入字母 d 宏任务处理</h3>
<input value={value1} onChange={onChange1}></input>
</div>
}

虽然能够让光标位置正确,但是多次输入的时候存在光标从最后面移动到原位置的情况

2) 微任务处理(关于微任务宏任务可以自行百度了解)
import { useState } from "react"
export default function () {
const [value2, setValue2] = useState(1234)
const onChange2 = (e) => {
const start = e.target.selectionStart
const inputValue = e.nativeEvent.target.value
const value = inputValue.replace('d', '')
const input = e.nativeEvent.target
setValue2(value)
new Promise(res => {
res()
// promist.then的回调函数属于微任务
}).then(() => {
inputValue.includes('d') && input.setSelectionRange(start - 1, start - 1)
})
} return <div style={{marginTop:200}}>
<h3>焦点修改实例:不允许输入字母 d 微任务处理</h3>
<input value={value2} onChange={onChange2}></input>
</div>
}

3.总结

输入框onChange修改value值导致的光标定位到最后的时机在微任务和宏任务的前面,

即 顺序为 1.重置光标 => 2.微任务 =>(浏览器内部重置光标)界面重新渲染 => 3.宏任务

其中使用宏任务二者执行间隔时间跨度大,导致重置光标界面已经发生变化,宏任务执行恢复光标,导致看到光标从最后移动到代码设置的位置(即:浏览器执行恢复光标 =>界面重新渲染 ,光标移动到最后 => 代码设置光标位置 => 浏览器重新渲染,恢复到代码设置的位置)

微任务则缩小了间隔或者说顺序 (即:浏览器执行恢复光标 => 代码设置光标位置 => 浏览器重新渲染,设置为代码设置的位置)

但是该代码仅仅处理了简单的情况即每次只输入一位的情况,还存在一些边界情况未处理,例如直接复制dddd,调整输入位置,粘贴就会导致光标位置后移,此种情况就需要对原值与新输入值做对比并进行处理

浏览器端实现类似input限制输入两位小数,输入时光标从输入位置移动到最后的更多相关文章

  1. input和React-Native的TextInput的输入限制,只能输入两位小数(阻止0开头的输入),类似价格限制

    一.背景: 想要实现一功能: 1. 最多只能输入两位小数,类似的价格限制 2. 实时监听限制输入,禁止输入不符合规范的字符(当输入违禁字符,进行删除操作) 这样做的优点: 1. 在用户输入时直接进行限 ...

  2. Android限定EditText的输入类型为数字或者英文(包括大小写),EditText,TextView只能输入两位小数

    Android限定EditText的输入类型为数字或者英文(包括大小写) // 监听密码输入框的输入内容类型,不可以输入中文    TextWatcher mTextWatcher = new Tex ...

  3. OC UITextField只允许输入两位小数

    //只能输入两位小数 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range r ...

  4. angularjs控制输入框只输入数字及最多输入两位小数

    ps:示例中作用在循环中,其它的你可以按实际需求进行修改使用 <input type="text" ng-model="item.productNumber&quo ...

  5. 转载:html+js实现只允许输入两位小数的输入框

    JS代码: <script language="JavaScript" type="text/javascript"> function clear ...

  6. 【devexpress】spinEdit控件如何设置只能输入两位小数

    只需设置对应的正则表达式即可,我这里设置的是n2意思就是两位小数的意思 效果如下

  7. ios TextField限制输入两位小数

    只需要实现textField的这个代理方法就可以实现 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange: ...

  8. 【前端开发】限制input输入保留两位小数

    <input type="text" name='amount' id="cash_num" placeholder="请输入金额" ...

  9. 【jQuery、原生】键盘键入两位小数

    jquery的处理办法 <!doctype html> <html lang="en"> <head> <meta charset=&qu ...

  10. codevs 1206 保留两位小数

    http://codevs.cn/problem/1206/ 1206 保留两位小数  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 青铜 Bronze 题解  查看运行结果 ...

随机推荐

  1. Failed to collect dependencies at com.oneconnect......-Intellij-IDEA-使用maven打包采坑记录

    一.问题由来 由于刚开始使用Intellij-IDEA,使用不是很熟练,因此使用过程中出现各种各样的问题.最近开发过程中,准备使用IDEA打包项目发布到测试服务器,报错信息如下: Failed to ...

  2. 适用mybatis和jpa的全数据库类型主键生成插件,分布式高并发有序id生成器

    适用mybatis和jpa的全数据库类型主键生成插件,分布式高并发有序id生成器

  3. deepin平台安装debian的cao蛋时

    我在deepin系统安装别的系统的时候,一直在boot界面无法进行下一步.困扰了我好几天,最后从电脑的左侧换成了电脑的右侧(usb)接口. 终于安装成功.你是......牛(deepin)

  4. stm32 文件系统数据读写源码解析

    一 概念 fatfs文件系统在文件读写中不可或却.熟悉和深入理解是一个不可或缺的前提. 这里面需要先明确几个概念:文件open的属性,这个非常重要.可以并列使用. 二  源码解析 A  写入数据: i ...

  5. 脑电测量ADS1299芯片调试总结

    问题一:读出来ID不对? 笔者经过查阅官网资料和测试,发现这个一般是上电或者启动次序不对引起的. 特别是上电次序不同会导致这类问题. 问题二:内部时钟和外部时钟的选择是什么? 就拿内部时钟来说吧,首先 ...

  6. c语言随笔

    c语言随笔 整型数据类型 unsigned int [signed] int [signed] short [int] unsigned long long [int] // long long 为c ...

  7. Ubuntu 14.04 升级到Gnome3.12z的折腾之旅(警示后来者)+推荐Extensions.-------(一)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文发布于 2014-12-19 22:40:20 ...

  8. Vulnhub靶场--EVILBOX: ONE

    环境配置 靶机连接 攻击者主机IP:192.168.47.130 目标主机IP:192.168.47.131 信息搜集 扫描目标主机,发现目标主机开放了22.80端口 ┌──(kali㉿kali)-[ ...

  9. Java CC链全分析

    CC链全称CommonsCollections(Java常用的一个库) 梦的开始CC1 环境部署 JDK版本:jdk8u65 Maven依赖: <dependencies> <!-- ...

  10. Vue3.0里为什么要用 Proxy API 替代 defineProperty API ?

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 一.Object.defineProperty 定义:Object.defineProperty() 方法会直接在一个对象上定义一个新属性 ...